Browse Source

JSON to PGN parser

master
DHTMLGoodies 5 years ago
parent
commit
126dc9b599
  1. 2
      GameParser.php
  2. 113
      JsonToPgnParser.php
  3. 1
      autoload.php
  4. 106
      test/JSONToPgnTest.php
  5. 5
      test/ParserTest.php
  6. 58
      test/pgn/annotated.pgn

2
GameParser.php

@ -37,8 +37,6 @@ class GameParser
private function parseAMove(&$move)
{
if (!isset($move[CHESS_JSON::MOVE_NOTATION]) || (isset($move[CHESS_JSON::FEN]) && isset($move[CHESS_JSON::MOVE_FROM]) && isset($move[CHESS_JSON::MOVE_TO]))) {
return;
}

113
JsonToPgnParser.php

@ -0,0 +1,113 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: alfmagne1
* Date: 13/03/2017
* Time: 19:00
*/
class JsonToPgnParser
{
private $games;
public function __construct()
{
$this->games = array();
}
/**
* @param string $jsonString
*/
public function addGame($jsonString)
{
$this->addGameObject(json_decode($jsonString, true));
}
/**
* @param array $json
*/
public function addGameObject($json)
{
$this->games[] = $json;
}
public function asPgn()
{
$ret = array();
foreach ($this->games as $game) {
$ret[] = $this->gameToPgn($game);
}
return implode("\n\n", $ret);
}
private function gameToPgn($game)
{
$moves = array();
$metadata = array();
foreach ($game as $key => $value) {
switch ($key) {
case "moves":
$moves = $this->movesToPgn($value, $this->getStartMove($game));
break;
default:
if (is_string($value)) {
$metadata[] = '[' . ucfirst($key) . ' "' . $value . '"]';
}
}
}
return implode("\n", $metadata) . "\n\n" . $moves;
}
private function getStartMove($game)
{
if (empty($game["fen"])) return 1;
$tokens = explode(" ", $game["fen"]);
$ret = array_pop($tokens);
if ($tokens[1] == "b") $ret += .5;
return $ret;
}
private function movesToPgn($moves, $startMove)
{
$ret = array();
if ($startMove != floor($startMove)) {
$ret[] = floor($startMove) . "...";
}
foreach ($moves as $move) {
if(!empty($move["m"])){
if ($startMove == floor($startMove)) {
$ret[] = $startMove . ".";
}
$ret[] = str_replace("..", "", $move["m"]);
}
if (!empty($move["comment"])) {
$ret[] = '{' . $move["comment"] . "}";
}
if(!empty($move["variations"])){
foreach($move["variations"] as $variation){
if(!empty($variation)){
$ret[] = "(" . $this->movesToPgn($variation, $startMove);
}
}
}
if(!empty($move["m"])) {
$startMove += .5;
}
}
return implode(" ", $ret);
}
}

1
autoload.php

@ -7,6 +7,7 @@ spl_autoload_register(
static $classes = null;
if ($classes === null) {
$classes = array(
'jsontopgnparser' => '/JsonToPgnParser.php',
'chess_json' => '/CHESS_JSON.php',
'board0x88config' => '/Board0x88Config.php',
'dgtgameparser' => '/DGTGameParser.php',

106
test/JSONToPgnTest.php

@ -0,0 +1,106 @@
<?php
/**
* Created by IntelliJ IDEA.
* User: alfmagne1
* Date: 13/03/2017
* Time: 19:01
*/
require_once(__DIR__ . "/../autoload.php");
class JSONToPgnTest extends PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function shouldBeAbleToAddGames()
{
// given
$json = $this->gameAsJson();
$parser = new JsonToPgnParser();
// when
$parser->addGame($json);
$pgn = $parser->asPgn();
// then
/*
* [Event "4th match"]
[Site "London"]
[Date "1834.??.??"]
[Round "62"]
[White "McDonnell,A"]
[Black "De La Bourdonnais,L"]
[Result "0-1"]
1.e4 c5 2.Nf3 Nc6 3.d4 cxd4 4.Nxd4 e5 5.Nxc6 bxc6 6.Bc4 Nf6 7.Bg5 Be7 8.Qe2 d5 9.Bxf6 Bxf6 10.Bb3 O-O 11.O-O a5 12.exd5 cxd5 13.Rd1 d4 14.c4 Qb6 15.Bc2 Bb7 16.Nd2 Rae8 17.Ne4 Bd8 18.c5 Qc6 19.f3 Be7 20.Rac1 f5 21.Qc4+ Kh8 22.Ba4 Qh6 23.Bxe8 fxe4 24.c6 exf3 25.Rc2 Bc8 26.Bd7 Qe3+ 27.Kh1 f2 28.Rf1 d3 29.Rc3 Bxd7 30.cxd7 e4 31.Qc8 Bd8 32.Qc4 Qe1 33.Rc1 d2 34.Qc5 Rg8 35.Rd1 e3 36.Qc3 Qxd1 37.Rxd1 e2 0-1
*/
$this->assertContains('[Event "4th match"]', $pgn);
$this->assertContains('[Date "1834.??.??"]', $pgn);
$this->assertContains('1. e4 c5 2. Nf3 Nc6 3. d4 cxd4', $pgn);
}
/**
* @test
*/
public function shouldGetAnnotations()
{
$parser = new JsonToPgnParser();
$json = $this->getAnnotated();
$parser->addGame($json);
// when
$pgn = $parser->asPgn();
// then
$this->assertContains('{In my preparation to this tournament, I (and probably everybody else) paid the most serious', $pgn);
}
/**
* @test
*/
public function shouldGetVariations(){
$parser = new JsonToPgnParser();
$json = $this->getAnnotated();
$parser->addGame($json);
// when
$pgn = $parser->asPgn();
// then
$this->assertContains('(16... h6 17. Be3 {is much better for White, since his rook ', $pgn);
}
private function getAnnotated()
{
$parser = new PgnParser("pgn/annotated.pgn");
$games = $parser->getGames();
return json_encode($games[0]);
}
private function gamesAsJson()
{
$games = $this->getGames();
return json_encode($games);
}
private function gameAsJson()
{
$games = $this->getGames();
$game = $games[0];
return json_encode($game);
}
private function getGames()
{
$parser = new PgnParser("pgn/greatgames.pgn");
return $parser->getGames();
}
}

5
test/ParserTest.php

@ -2223,8 +2223,7 @@ Rc8 Ne6+ 72. Kf6 d2 73. c5+ Kd7 0-1';
$parser = new PgnParser("pgn/nullmoves.pgn");
$game = $parser->getGameByIndex(0);
// No exception
$this->assertCount(5, $game["moves"] );
}
}

58
test/pgn/annotated.pgn

@ -0,0 +1,58 @@
[Event ""]
[Site ""]
[Date ""]
[White "Svidler"]
[Black "Shirov"]
[Result "1-0"]
[Source "Russian Chess"]
[Annotator "Svidler"]
1. e4 e5
{In my preparation to this tournament, I (and probably everybody else) paid the most serious attention to two openingsx Ruy Lopez with Bc5 and Najdorf, since most of the participants seem to play them both. Needless to say, refuting Najdorf is tough, but I thought I came close to refuting Ruy Lopez with 5...b5 and 6...Bc5, provided Black responded to 7.a4 with 7...Rb8. But the opening ceremony dealt a heavy blow to mex I was the last one to play Shirov with White. And indeed, in Rounds 7&8 Shirov faced the position after 7.a4 against Kasparov & Anand. But to my relief, he must have thought that these guys know something and replied 7...Bb7. I was still in business.}
2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O b5 6. Bb3 Bc5 7. a4 Rb8
{Played without hesitation, as I and Nigel correctly guessed he wouldx his 7...Bb7 was not broken, but quite bent in the game vs Vishy, and also I probably don't give the impression of a man capable to prepare anything at all.}
8. c3 d6 9. d4 Bb6 10. Na3 Bg4 11. axb5 axb5 12. Nxb5 O-O
{One of the strangest tabyias of modern times. Black is a pawn down and is prepared to take on f3, strengthening White's centre and giving him the advantage of two Bishops.}
13. Re1
{This position saw also 13.Bc2 and 13.Be3, but Black is doing relatively fine there.}
13...Bxf3 14. gxf3 Nh5
{Shirov is repeating his game vs Ivanchuk from Belgrade, where he had no problems whatsoever.}
15. Kh1 $1
{Novelty which, in my opinion, almost kills the entire line. Kasparov, however, seemed to be sceptical. During the closing ceremony he asked me a couple of questions concerning the game, and then remarked that he would do a far better job as White if he was given a chance. It remains a mystery whether his improvement over my play was before or after move 15. Anand, on the other hand, is rumoured to have prepared the same stuff. } (15.Be3 Qf6 16.Kh1 exd4 17.cxd4 Ba5 $1 18.Rg1 Rxb5 19.Ba4 Rxb2 20.Bxc6 Bb6) { was played in Ivanchuk-Shirov. Black is completely out of danger.}
15...Qf6
{Played very quickly again. Other moves arex } (15...Qh4 16.Be3 exd4 17.cxd4 Ba5 18.Nc3 { and since Black queen is not attacking f3, White is just a pawn up. })
(15...exd4 16.Nxd4 $1 (16.cxd4 $6 Qf6 17.Be3 Ba5 {transposes to Ivanchuk-Shirov}) 16...Bxd4 (16...Nxd4 17.cxd4 Qf6 18.Ra4+) 17.cxd4 Nxd4 (17...Qf6 18.Ra4+) 18.Qxd4 Rxb3 { and here comes the highpoint of White's ideax } 19.Qd5 $1 $20)
16. Rg1 $1
{Winning an important tempo.}
16...Nf4
(16...h6 17.Be3 {is much better for White, since his rook is on g1 and cannot be attacked by Ba5 }) (16...exd4 17.Bg5 Qe5 18.Bd5+)
17. Be3 Ne6 $133
{The only possible source of counterplay.}
18. Bxe6 fxe6 19. Rg3 Kh8 $1
{A good prophylactic move} (19...exd4 20.Nxd4 $5 (20.cxd4 {is also OK, since} 20...e5 {is bad} 21.Bg5 $1 Qf7 22.Bh6 $20) 20...Ne5 (20...Bxd4 21.cxd4 Rxb2 22.Rc1 Ne7 23.Bg5 $1 Qf7 24.Rxc7 $20) 21.f4 Nc4 22.Qe2 Nxe3 (22...Nxb2 23.Ra2 $20) 23.fxe3+)
20. Qd3
{This move does not spoil anything, but it was probably better to play 20.Rc1, and Black is left with almost no counterplay at all.}
20...exd4 21. cxd4 e5 22. d5
(22.Rc1 $2 Nxd4 23.Bxd4 exd4 24.Nxc7 $4 Rbc8 $21)
22...Ne7
{Here I spent half an hour calculating this position to the end, and played}
23. Bxb6 Rxb6 24. Nxc7 Rxb2
(24...Ng6 25.Ne6 Nf4 26.Qe3 $20)
25. Ne6 Rg8 26. Kg1 $1
{Many other ideas are tempting, but this is the best. White chases away the enemy rook and then goes on the offensive.}
26...Ng6 27. Qa3 Rb6
(27...Rc2 $5 {A very nice variation could happen if Black went} 28.Qxd6 Nf4 {Here Black's initiative is quite strong, so White returns some of the material: } 29.Qd7 Ne2+ (29...Rgc8 30.Rf1 Ne2+ 31.Kg2 Nxg3 32.hxg3 R2c3 33.f4 exf4 34.Nxf4 $20) 30.Kg2 Nxg3 31.hxg3 Rc3 $1 32.f4 $1 {going for it!} 32...exf4 33.Nxf4 Rxg3+ 34.fxg3 Qb2+ $1 (34...Qxa1 {is a big mistakex } 35.Ng6+ hxg6 36.Qh3#) 35.Kf3 Qc3+ 36.Ke2 Qb2+ 37.Kd3 Qb3+ 38.Kd4 Qb2+ (38...Qb4+ 39.Ke5 Qb6 $5 {trying to discoordinate White's pieces} 40.Qe7 $1 Qb2+ 41.Ke6 Qxa1 {and once again} 42.Ng6+ hxg6 43.Qh4#) 39.Kc5 Qc3+ 40.Kd6 Qb4+ (40...Qf6+ 41.Qe6 Rd8+ 42.Kc7 $20) 41.Ke6 Qxe4+ 42.Kf7 {what a journey!} 42...g5 43.Qe6 Rg7+ 44.Kf6 Qd4+ 45.Qe5 $20)
28. Kh1 $1
{The point. White is perfectly coordinated and is ready to tie Black completely with 29.Rag1.}
28...Nf4 $2
({During the game I was very worried about} 28...Nf8 $5. {I had seen the right ideax} 29.Qa7 $1 Rb3 $1 30.Ng5 h6 31.Nf7+ Kh7 32.Rh3 $1 ({after} 32.Rag1 $2 {with idea 33.Nxd6} Rxf3 $1) {Black is suddenly even better and Black is forced to go for} 32...Rxf3 (32...Ng6 33.Rxh6+ gxh6 34.Ng5+ Kh8 35.Qh7#) 33.Ng5+ Qxg5 34.Rxf3 $20})
29. Nxg7 Ne2 30. Nf5 $1
{That's what Alexei probably missed. White has no intention of protecting the exchange - once Black take on g3, the game will be over.}
30...Rgb8 31. Qd3 Rb2 32. Rf1 $1
{Probably something like 32.Rg4 was winning also, but this move is better- Black will be forced to take on g3 quite soon.}
32...Ra8
(32...Nxg3+ 33.hxg3 R2b3 34.Qd1 $1 (34.Qe2 Rb1 {with some chances}) 34...Rb1 35.Qxb1 Rxb1 36.Rxb1 {offers no hopes.})
33. Qc4 Nxg3+ 34. hxg3
{White is now winning easily.}
34...Qd8 35. Qc1 Rb3 36. Kg2 Qf8 37. Qc7
1-0
Loading…
Cancel
Save