From 87fdab816d29839a8f5d1493aa4f5b0f0d40e9da Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Sun, 17 Aug 2025 13:47:36 +0200 Subject: [PATCH] Support color specific enPassantRegion (#900) --- .github/copilot-instructions.md | 2 +- src/parser.cpp | 5 ++++- src/position.cpp | 14 +++++++------- src/variant.cpp | 6 ++++-- src/variant.h | 2 +- src/variants.ini | 2 ++ 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 1ac766b..611774a 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -152,7 +152,7 @@ tests/ # Test scripts and data - [Chess Variants on Chess.com](https://www.chess.com/variants) ### Development Best Practices -* Make sure to only stage and commit changes that are intended to be part of the task. +* Make sure to only stage and commit changes that were changed as part of the task, do not simply add all changes. * Keep changes minimal and focused on the task at hand. * After applying changes make sure that all places related to the task have been identified. * Stay consistent with the existing code style and conventions. diff --git a/src/parser.cpp b/src/parser.cpp index 9f2f848..cbd2404 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -426,7 +426,10 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("doubleStepRegionBlack", v->doubleStepRegion[BLACK]); parse_attribute("tripleStepRegionWhite", v->tripleStepRegion[WHITE]); parse_attribute("tripleStepRegionBlack", v->tripleStepRegion[BLACK]); - parse_attribute("enPassantRegion", v->enPassantRegion); + parse_attribute("enPassantRegion", v->enPassantRegion[WHITE]); + parse_attribute("enPassantRegion", v->enPassantRegion[BLACK]); + parse_attribute("enPassantRegionWhite", v->enPassantRegion[WHITE]); + parse_attribute("enPassantRegionBlack", v->enPassantRegion[BLACK]); parse_attribute("enPassantTypes", v->enPassantTypes[WHITE], v->pieceToChar); parse_attribute("enPassantTypes", v->enPassantTypes[BLACK], v->pieceToChar); parse_attribute("enPassantTypesWhite", v->enPassantTypes[WHITE], v->pieceToChar); diff --git a/src/position.cpp b/src/position.cpp index c55ab3f..2488a71 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -447,7 +447,7 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, // a) side to move have a pawn threatening epSquare // b) there is an enemy pawn one or two (for triple steps) squares in front of epSquare // c) there is no (non-wall) piece on epSquare or behind epSquare - if ( (var->enPassantRegion & epSquare) + if ( (var->enPassantRegion[sideToMove] & epSquare) && ( !var->fastAttacks || (var->enPassantTypes[sideToMove] & ~piece_set(PAWN)) || ( pawn_attacks_bb(~sideToMove, epSquare) & pieces(sideToMove, PAWN) @@ -1607,7 +1607,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { st->captureSquare = capsq; assert(st->epSquares & to); - assert(var->enPassantRegion & to); + assert(var->enPassantRegion[us] & to); assert(piece_on(to) == NO_PIECE); } @@ -1844,7 +1844,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { && ( std::abs(int(to) - int(from)) == 2 * NORTH || std::abs(int(to) - int(from)) == 3 * NORTH)) { - if ( (var->enPassantRegion & (to - pawn_push(us))) + if ( (var->enPassantRegion[them] & (to - pawn_push(us))) && ((pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN)) && !(walling() && gating_square(m) == to - pawn_push(us))) { @@ -1852,7 +1852,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { k ^= Zobrist::enpassant[file_of(to)]; } if ( std::abs(int(to) - int(from)) == 3 * NORTH - && (var->enPassantRegion & (to - 2 * pawn_push(us))) + && (var->enPassantRegion[them] & (to - 2 * pawn_push(us))) && ((pawn_attacks_bb(us, to - 2 * pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN)) && !(walling() && gating_square(m) == to - 2 * pawn_push(us))) { @@ -1924,7 +1924,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { && ((PseudoMoves[1][us][type_of(pc)][from] & ~PseudoMoves[0][us][type_of(pc)][from]) & to)) { assert(type_of(pc) != PAWN); - st->epSquares = between_bb(from, to) & var->enPassantRegion; + st->epSquares = between_bb(from, to) & var->enPassantRegion[them]; for (Bitboard b = st->epSquares; b; ) k ^= Zobrist::enpassant[file_of(pop_lsb(b))]; } @@ -2229,7 +2229,7 @@ void Position::undo_move(Move m) { capsq = st->captureSquare; assert(st->previous->epSquares & to); - assert(var->enPassantRegion & to); + assert(var->enPassantRegion[sideToMove] & to); assert(piece_on(capsq) == NO_PIECE); } @@ -3237,7 +3237,7 @@ bool Position::pos_is_ok() const { if ( (sideToMove != WHITE && sideToMove != BLACK) || (count(WHITE) && piece_on(square(WHITE)) != make_piece(WHITE, KING)) || (count(BLACK) && piece_on(square(BLACK)) != make_piece(BLACK, KING)) - || (ep_squares() & ~var->enPassantRegion)) + || (ep_squares() & ~(var->enPassantRegion[WHITE] | var->enPassantRegion[BLACK]))) assert(0 && "pos_is_ok: Default"); if (Fast) diff --git a/src/variant.cpp b/src/variant.cpp index c8aa137..ad97b97 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -471,7 +471,8 @@ namespace { Variant* v = chess_variant_base()->init(); v->startFen = "rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPP w kq - 0 1"; v->doubleStepRegion[WHITE] |= Rank1BB; - v->enPassantRegion = Rank3BB | Rank6BB; // exclude en passant on second rank + v->enPassantRegion[WHITE] = Rank6BB; // exclude en passant on second rank + v->enPassantRegion[BLACK] = Rank3BB; // exclude en passant on second rank v->extinctionValue = -VALUE_MATE; v->extinctionPieceTypes = piece_set(ALL_PIECES); return v; @@ -1073,7 +1074,8 @@ namespace { v->nMoveRuleTypes[BLACK] = piece_set(CUSTOM_PIECE_1); v->promotionPieceTypes[BLACK] = piece_set(COMMONER) | DRAGON | ARCHBISHOP | CUSTOM_PIECE_2 | CUSTOM_PIECE_3; v->promotionLimit[COMMONER] = 2; - v->enPassantRegion = 0; + v->enPassantRegion[WHITE] = 0; + v->enPassantRegion[BLACK] = 0; v->extinctionPieceCount = 0; v->extinctionPseudoRoyal = true; v->dupleCheck = true; diff --git a/src/variant.h b/src/variant.h index c13305d..0e6d44c 100644 --- a/src/variant.h +++ b/src/variant.h @@ -71,7 +71,7 @@ struct Variant { bool doubleStep = true; Bitboard doubleStepRegion[COLOR_NB] = {Rank2BB, Rank7BB}; Bitboard tripleStepRegion[COLOR_NB] = {}; - Bitboard enPassantRegion = AllSquares; + Bitboard enPassantRegion[COLOR_NB] = {AllSquares, AllSquares}; PieceSet enPassantTypes[COLOR_NB] = {piece_set(PAWN), piece_set(PAWN)}; bool castling = true; bool castlingDroppedPiece = false; diff --git a/src/variants.ini b/src/variants.ini index 24dc66d..f2e06ba 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -193,6 +193,8 @@ # tripleStepRegionWhite: region where pawn triple steps are allowed for white [Bitboard] (default: -) # tripleStepRegionBlack: region where pawn triple steps are allowed for black [Bitboard] (default: -) # enPassantRegion: define region (target squares) where en passant is allowed after double steps [Bitboard] (default: AllSquares) +# enPassantRegionWhite: define region (target squares) where en passant is allowed for white [Bitboard] (default: AllSquares) +# enPassantRegionBlack: define region (target squares) where en passant is allowed for black [Bitboard] (default: AllSquares) # enPassantTypes: define pieces able to capture en passant [PieceSet] (default: p) # enPassantTypesWhite: define white pieces able to capture en passant [PieceSet] (default: p) # enPassantTypesBlack: define black pieces able to capture en passant [PieceSet] (default: p) -- 1.7.0.4