From 11a516028a642158ef6965c6c47826939eb59d57 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Sat, 1 Apr 2023 12:40:24 +0200 Subject: [PATCH] Fix shako castling when rook in corner (#617) --- src/parser.cpp | 2 ++ src/position.cpp | 4 ++-- src/variant.cpp | 2 ++ src/variant.h | 2 ++ src/variants.ini | 2 ++ test.py | 15 +++++++++++---- tests/perft.sh | 1 + 7 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index a4142cd..dbde7ed 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -378,6 +378,8 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("castlingKingPiece", v->castlingKingPiece[BLACK], v->pieceToChar); parse_attribute("castlingKingPieceWhite", v->castlingKingPiece[WHITE], v->pieceToChar); parse_attribute("castlingKingPieceBlack", v->castlingKingPiece[BLACK], v->pieceToChar); + parse_attribute("castlingRookKingsideFile", v->castlingRookKingsideFile); + parse_attribute("castlingRookQueensideFile", v->castlingRookQueensideFile); parse_attribute("castlingRookPieces", v->castlingRookPieces[WHITE], v->pieceToChar); parse_attribute("castlingRookPieces", v->castlingRookPieces[BLACK], v->pieceToChar); parse_attribute("castlingRookPiecesWhite", v->castlingRookPieces[WHITE], v->pieceToChar); diff --git a/src/position.cpp b/src/position.cpp index d9e798f..6053429 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -349,10 +349,10 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, token = char(toupper(token)); if (token == 'K') - for (rsq = make_square(FILE_MAX, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; --rsq) {} + for (rsq = make_square(var->castlingRookKingsideFile, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; --rsq) {} else if (token == 'Q') - for (rsq = make_square(FILE_A, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; ++rsq) {} + for (rsq = make_square(var->castlingRookQueensideFile, castling_rank(c)); !(castling_rook_pieces(c) & type_of(piece_on(rsq))) || color_of(piece_on(rsq)) != c; ++rsq) {} else if (token >= 'A' && token <= 'A' + max_file()) rsq = make_square(File(token - 'A'), castling_rank(c)); diff --git a/src/variant.cpp b/src/variant.cpp index 9bdc17e..265afe8 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -1579,6 +1579,8 @@ namespace { v->promotionRegion[BLACK] = Rank1BB; v->castlingKingsideFile = FILE_H; v->castlingQueensideFile = FILE_D; + v->castlingRookKingsideFile = FILE_I; + v->castlingRookQueensideFile = FILE_B; v->castlingRank = RANK_2; v->doubleStepRegion[WHITE] = Rank3BB; v->doubleStepRegion[BLACK] = Rank8BB; diff --git a/src/variant.h b/src/variant.h index d316779..e1a460a 100644 --- a/src/variant.h +++ b/src/variant.h @@ -77,6 +77,8 @@ struct Variant { Rank castlingRank = RANK_1; File castlingKingFile = FILE_E; PieceType castlingKingPiece[COLOR_NB] = {KING, KING}; + File castlingRookKingsideFile = FILE_MAX; // only has to match if rook is not in corner in non-960 variants + File castlingRookQueensideFile = FILE_A; // only has to match if rook is not in corner in non-960 variants PieceSet castlingRookPieces[COLOR_NB] = {piece_set(ROOK), piece_set(ROOK)}; PieceType kingType = KING; bool checking = true; diff --git a/src/variants.ini b/src/variants.ini index 409d424..85be25b 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -183,6 +183,8 @@ # castlingRank: relative rank of castling [Rank] (default: 1) # castlingKingFile: starting file of the castlingKingPiece if there can be more than one of that type [File] (default: e) # castlingKingPiece: first piece type that participates in castling [PieceType] (default: k) +# castlingRookKingsideFile: starting file of castlinRookPieces on kingside (if not in corner) [File] (default: l) +# castlingRookQueensideFile: starting file of castlinRookPieces on queenside (if not in corner) [File] (default: a) # castlingRookPieces: second piece type that participates in castling [PieceSet] (default: r) # checking: allow checks [bool] (default: true) # dropChecks: allow checks by piece drops [bool] (default: true) diff --git a/test.py b/test.py index f1c4cdc..3ffd61a 100644 --- a/test.py +++ b/test.py @@ -312,6 +312,11 @@ class TestPyffish(unittest.TestCase): self.assertIn("d6d7m", result) self.assertNotIn("d6d7", result) + # Test configurable piece perft + legals = ['a3a4', 'b3b4', 'c3c4', 'd3d4', 'e3e4', 'f3f4', 'g3g4', 'e1e2', 'f1f2', 'b1a2', 'b1b2', 'b1c2', 'c1b2', 'c1c2', 'c1d2', 'a1a2', 'g1g2', 'd1c2', 'd1d2', 'd1e2'] + result = sf.legal_moves("yarishogi", sf.start_fen("yarishogi"), []) + self.assertCountEqual(legals, result) + def test_short_castling(self): legals = ['f5f4', 'a7a6', 'b7b6', 'c7c6', 'd7d6', 'e7e6', 'i7i6', 'j7j6', 'a7a5', 'b7b5', 'c7c5', 'e7e5', 'i7i5', 'j7j5', 'b8a6', 'b8c6', 'h6g4', 'h6i4', 'h6j5', 'h6f7', 'h6g8', 'h6i8', 'd5a2', 'd5b3', 'd5f3', 'd5c4', 'd5e4', 'd5c6', 'd5e6', 'd5f7', 'd5g8', 'j8g8', 'j8h8', 'j8i8', 'e8f7', 'c8b6', 'c8d6', 'g6g2', 'g6g3', 'g6f4', 'g6g4', 'g6h4', 'g6e5', 'g6g5', 'g6i5', 'g6a6', 'g6b6', 'g6c6', 'g6d6', 'g6e6', 'g6f6', 'g6h8', 'f8f7', 'f8g8', 'f8i8'] moves = ['b2b4', 'f7f5', 'c2c3', 'g8d5', 'a2a4', 'h8g6', 'f2f3', 'i8h6', 'h2h3'] @@ -332,10 +337,12 @@ class TestPyffish(unittest.TestCase): result = sf.legal_moves("diana", "rbnk1r/pppbpp/3p2/5P/PPPPPB/RBNK1R w KQkq - 2 3", []) self.assertIn("d1f1", result) - # Test configurable piece perft - legals = ['a3a4', 'b3b4', 'c3c4', 'd3d4', 'e3e4', 'f3f4', 'g3g4', 'e1e2', 'f1f2', 'b1a2', 'b1b2', 'b1c2', 'c1b2', 'c1c2', 'c1d2', 'a1a2', 'g1g2', 'd1c2', 'd1d2', 'd1e2'] - result = sf.legal_moves("yarishogi", sf.start_fen("yarishogi"), []) - self.assertCountEqual(legals, result) + # Check that in variants where castling rooks are not in the corner + # the castling rook is nevertheless assigned correctly + result = sf.legal_moves("shako", "c8c/ernbqkbnre/pppppppppp/10/10/10/10/PPPPPPPPPP/5K2RR/10 w Kkq - 0 1", []) + self.assertIn("f2h2", result) + result = sf.legal_moves("shako", "c8c/ernbqkbnre/pppppppppp/10/10/10/10/PPPPPPPPPP/RR3K4/10 w Qkq - 0 1", []) + self.assertIn("f2d2", result) def test_get_fen(self): result = sf.get_fen("chess", CHESS, []) diff --git a/tests/perft.sh b/tests/perft.sh index ec08d5f..92d6ebb 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -172,6 +172,7 @@ if [[ $1 == "all" || $1 == "largeboard" ]]; then expect perft.exp shako "fen 4kc3c/ernbq1b1re/ppp3p1pp/3p2pp2/4p5/5P4/2PN2P3/PP1PP2PPP/ER1BQKBNR1/5C3C w KQ - 0 9" 3 26325 > /dev/null expect perft.exp shako "fen 4ncr1k1/1cr2P4/pp2p2pp1/P7PN/2Ep1p4/B3P1eN2/2P1n1P3/1B1P1K4/9p/5C2CR w - - 0 1" 3 180467 > /dev/null expect perft.exp shako "fen r5k3/4q2c2/1ebppnp3/1pp3BeEQ/10/2PE2P3/1P3P4/5NP2P/rR3KB3/7C2 w Q - 3 35" 2 4940 > /dev/null + expect perft.exp shako "fen 10/rr3k4/ppppp5/10/10/10/10/6PPPP/5K2RR/10 w Kq - 0 1" 2 460 > /dev/null expect perft.exp xiangqi startpos 4 3290240 > /dev/null expect perft.exp xiangqi "fen 1rbaka2R/5r3/6n2/2p1p1p2/4P1bP1/PpC3Bc1/1nPR2P2/2N2AN2/1c2K1p2/2BAC4 w - - 0 1" 4 4485547 > /dev/null expect perft.exp xiangqi "fen 4kcP1N/8n/3rb4/9/9/9/9/3p1A3/4K4/5CB2 w - - 0 1" 4 92741 > /dev/null -- 1.7.0.4