From f114eedd726a3121565976afa77507f424565977 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Thu, 9 Jan 2025 19:49:43 +0100 Subject: [PATCH] Fix FEN parsing for S-Chess Closes #855. --- src/position.cpp | 14 ++++++++------ test.py | 11 +++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index 40fa6e32c..5026a6f64 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -384,17 +384,16 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, : make_square(castling_king_file(), castling_rank(c)); // Skip invalid castling rights if (!(castlingKings & st->castlingKingSquare[c])) - { st->castlingKingSquare[c] = SQ_NONE; - continue; - } } // Set gates (and skip castling rights) if (gating()) { - st->gatesBB[c] |= rsq; - if (token == 'K' || token == 'Q') + // Only add gates for occupied squares + if (pieces(c) & rsq) + st->gatesBB[c] |= rsq; + if ((token == 'K' || token == 'Q') && st->castlingKingSquare[c] != SQ_NONE) st->gatesBB[c] |= st->castlingKingSquare[c]; // Do not set castling rights for gates unless there are no pieces in hand, // which means that the file is referring to a chess960 castling right. @@ -402,7 +401,10 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, continue; } - if (castling_enabled() && (castling_rook_pieces(c) & type_of(piece_on(rsq))) && color_of(piece_on(rsq)) == c) + // Only add castling right if both king and rook are on expected squares + if ( castling_enabled() + && st->castlingKingSquare[c] != SQ_NONE + && (castling_rook_pieces(c) & type_of(piece_on(rsq))) && color_of(piece_on(rsq)) == c) set_castling_right(c, rsq); } diff --git a/test.py b/test.py index 919891470..f235748d1 100644 --- a/test.py +++ b/test.py @@ -337,6 +337,11 @@ def test_legal_moves(self): result = sf.legal_moves("shogun", SHOGUN, ["c2c4", "b8c6", "b2b4", "b7b5", "c4b5", "c6b8"]) self.assertIn("b5b6+", result) + # Seirawan gating but no castling + fen = "rnbq3r/pp2bkpp/8/2p1p2K/2p1P3/8/PPPP1PPP/RNB4R[EHeh] b ABCHabcdh - 0 10" + result = sf.legal_moves("seirawan", fen, []) + self.assertIn("c8g4h", result) + # In Cannon Shogi the FGC and FSC can also move one square diagonally and, besides, # move or capture two squares diagonally, by leaping an adjacent piece. fen = "lnsg1gsnl/1rc1kuab1/p1+A1p1p1p/3P5/6i2/6P2/P1P1P3P/1B1U1ICR1/LNSGKGSNL[] w - - 1 3" @@ -460,6 +465,12 @@ def test_get_fen(self): result = sf.get_fen("seirawan", fen0, ["e8g8"]) self.assertEqual(result, fen1) + # handle invalid castling/gating flags + fen0 = "rnbq3r/pp2bkpp/8/2p1p2K/2p1P3/8/PPPP1PPP/RNB4R[EHeh] b QBCEHabcdk - 0 10" + fen1 = "rnbq3r/pp2bkpp/8/2p1p2K/2p1P3/8/PPPP1PPP/RNB4R[EHeh] b ABCHabcdh - 0 10" + result = sf.get_fen("seirawan", fen0, []) + self.assertEqual(result, fen1) + result = sf.get_fen("chess", CHESS, [], True, False, False) self.assertEqual(result, CHESS960)