Fix PGN parsing 960 variants (#474)
authorBajusz Tamás <gbtami@users.noreply.github.com>
Thu, 12 May 2022 15:38:14 +0000 (17:38 +0200)
committerGitHub <noreply@github.com>
Thu, 12 May 2022 15:38:14 +0000 (17:38 +0200)
src/ffishjs.cpp
tests/js/test.js
tests/pgn/pychess-variants_YHEWvfWF.pgn [new file with mode: 0644]

index 94fe87a..3e7eb2b 100644 (file)
@@ -562,10 +562,14 @@ Game read_game_pgn(std::string pgn) {
         headersParsed = true;
         auto it = game.header.find("Variant");
         if (it != game.header.end()) {
-          game.variant = it->second;
+          game.is960 = it->second.find("960", it->second.size() - 3) != std::string::npos;
+          if (game.is960) {
+            game.variant = it->second.substr(0, it->second.size() - 3);
+          } else {
+            game.variant = it->second;
+          }
           std::transform(game.variant.begin(), game.variant.end(), game.variant.begin(),
           [](unsigned char c){ return std::tolower(c); });
-          game.is960 = it->second.find("960") != std::string::npos;
         }
 
         it = game.header.find("FEN");
index c4dc366..6e5ff61 100644 (file)
@@ -747,13 +747,14 @@ describe('ffish.validateFen(fen, uciVariant, chess960)', function () {
 describe('ffish.readGamePGN(pgn)', function () {
   it("it reads a pgn string and returns a game object", () => {
      fs = require('fs');
-     let pgnFiles = ['deep_blue_kasparov_1997.pgn', 'lichess_pgn_2018.12.21_JannLee_vs_CrazyAra.j9eQS4TF.pgn', 'c60_ruy_lopez.pgn', 'pychess-variants_zJxHRVm1.pgn', 'Syrov - Dgebuadze.pgn']
+     let pgnFiles = ['deep_blue_kasparov_1997.pgn', 'lichess_pgn_2018.12.21_JannLee_vs_CrazyAra.j9eQS4TF.pgn', 'c60_ruy_lopez.pgn', 'pychess-variants_zJxHRVm1.pgn', 'Syrov - Dgebuadze.pgn', 'pychess-variants_YHEWvfWF.pgn']
 
      let expectedFens = ["1r6/5kp1/RqQb1p1p/1p1PpP2/1Pp1B3/2P4P/6P1/5K2 b - - 14 45",
                          "3r2kr/2pb1Q2/4ppp1/3pN2p/1P1P4/3PbP2/P1P3PP/6NK[PPqrrbbnn] b - - 1 37",
                          "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3",
                          "r1bQkb1r/ppp1pppp/2P5/2n2q2/8/2N2N2/PPP2PPP/R1BEKB1R[Hh] b KQCFkqcf - 0 8",
-                         "5rk1/4p3/2p3rR/2p1P3/2Pp1B2/1P1P2P1/2N1n3/6K1 w - - 1 44"]
+                         "5rk1/4p3/2p3rR/2p1P3/2Pp1B2/1P1P2P1/2N1n3/6K1 w - - 1 44",
+                         "r1q3r1/pp3p2/2kN1bp1/8/3P1H2/6P1/PPP2BKP/R2E1R2[h] b acg - 0 20"]
 
      for (let idx = 0; idx < pgnFiles.length; ++idx) {
      let pgnFilePath = pgnDir + pgnFiles[idx];
@@ -764,12 +765,14 @@ describe('ffish.readGamePGN(pgn)', function () {
        }
        let game = ffish.readGamePGN(data);
 
-       const variant = game.headers("Variant").toLowerCase();
-       let board = new ffish.Board(variant);
+       const is960 = game.headers('Variant').endsWith('960');
+       const variant = game.headers('Variant').toLowerCase().replace('960', '');
+       const fen = game.headers('FEN');
+       let board = new ffish.Board(variant, fen, is960);
        const mainlineMoves = game.mainlineMoves().split(" ");
        for (let idx2 = 0; idx2 < mainlineMoves.length; ++idx2) {
            board.push(mainlineMoves[idx2]);
-           chai.expect(ffish.validateFen(board.fen(), variant)).to.equal(1);
+           chai.expect(ffish.validateFen(board.fen(), variant, is960)).to.equal(1);
        }
        chai.expect(board.fen()).to.equal(expectedFens[idx]);
        board.delete();
diff --git a/tests/pgn/pychess-variants_YHEWvfWF.pgn b/tests/pgn/pychess-variants_YHEWvfWF.pgn
new file mode 100644 (file)
index 0000000..de98f85
--- /dev/null
@@ -0,0 +1,15 @@
+[Event "PyChess rated game"]
+[Site "https://www.pychess.org/YHEWvfWF"]
+[Date "2021.07.03"]
+[Round "-"]
+[White "TheFinnisher"]
+[Black "SmartAlice"]
+[Result "1-0"]
+[TimeControl "180+2"]
+[WhiteElo "1947?"]
+[BlackElo "1592"]
+[Variant "Seirawan960"]
+[FEN "rnqkbnrb/pppppppp/8/8/8/8/PPPPPPPP/RNQKBNRB[HEhe] w HECBFQKhecbfqk - 0 1"]
+[SetUp "1"]
+
+1. g3 g6 2. Nc3 Nc6 3. f4 e5 4. fxe5 Nxe5 5. d4 Nc4 6. e3 Ne6 7. Bf2 c6 8. Nd2 Nxd2 9. Qxd2/H d5 10. O-O/Ed1 Ng5 11. Bg2 Bd7 12. e4 h6 13. exd5 Bh3 14. Qxg5+ hxg5 15. Hxg5+ Kc7/E 16. dxc6 Bxg2 17. Kxg2 Bf6 18. Hf4+ Ed6 19. Nb5+ Kxc6 20. Nxd6 1-0