From 1b5a7893d112a95c728878de14500e940708a5bd Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 15 Sep 2023 19:26:24 +0200 Subject: [PATCH] Support petrified (#713) --- src/parser.cpp | 2 +- src/position.cpp | 31 +++++++++++++++++++------------ src/variant.cpp | 17 +++++++++++++++++ src/variant.h | 2 +- src/variants.ini | 4 ++-- 5 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index f222a6bc1..4871446b6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -383,7 +383,7 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("blastOnCapture", v->blastOnCapture); parse_attribute("blastImmuneTypes", v->blastImmuneTypes, v->pieceToChar); parse_attribute("mutuallyImmuneTypes", v->mutuallyImmuneTypes, v->pieceToChar); - parse_attribute("petrifyOnCapture", v->petrifyOnCapture); + parse_attribute("petrifyOnCaptureTypes", v->petrifyOnCaptureTypes, v->pieceToChar); parse_attribute("petrifyBlastPieces", v->petrifyBlastPieces); parse_attribute("doubleStep", v->doubleStep); parse_attribute("doubleStepRegionWhite", v->doubleStepRegion[WHITE]); diff --git a/src/position.cpp b/src/position.cpp index a55d50b98..70912854a 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1129,6 +1129,9 @@ bool Position::legal(Move m) const { occupied &= ~square_bb(capture_square(kto)); if (capture(m) && blast_on_capture()) occupied &= ~((attacks_bb(kto) & ((pieces(WHITE) | pieces(BLACK)) ^ pieces(PAWN))) | kto); + // Petrifying a pseudo-royal piece is illegal + if (capture(m) && (var->petrifyOnCaptureTypes & type_of(moved_piece(m))) && (st->pseudoRoyals & from)) + return false; Bitboard pseudoRoyals = st->pseudoRoyals & pieces(sideToMove); Bitboard pseudoRoyalsTheirs = st->pseudoRoyals & pieces(~sideToMove); if (is_ok(from) && (pseudoRoyals & from)) @@ -1145,6 +1148,10 @@ bool Position::legal(Move m) const { // Self-explosions are illegal if (pseudoRoyals & ~occupied) return false; + // Petrifiable pseudo-royals can't capture + Bitboard attackerCandidatesTheirs = occupied & ~square_bb(kto); + for (PieceSet ps = var->petrifyOnCaptureTypes & extinction_piece_types(); ps;) + attackerCandidatesTheirs &= ~pieces(~us, pop_lsb(ps)); // Check for legality unless we capture a pseudo-royal piece if (!(pseudoRoyalsTheirs & ~occupied)) while (pseudoRoyals) @@ -1152,7 +1159,7 @@ bool Position::legal(Move m) const { Square sr = pop_lsb(pseudoRoyals); // Touching pseudo-royal pieces are immune if ( !(blast_on_capture() && (pseudoRoyalsTheirs & attacks_bb(sr))) - && (attackers_to(sr, occupied, ~us) & (occupied & ~square_bb(kto)))) + && (attackers_to(sr, occupied, ~us) & attackerCandidatesTheirs)) return false; } // Look for duple check @@ -1169,7 +1176,7 @@ bool Position::legal(Move m) const { Square sr = pop_lsb(pseudoRoyalCandidates); // Touching pseudo-royal pieces are immune if (!( !(blast_on_capture() && (pseudoRoyalsTheirs & attacks_bb(sr))) - && (attackers_to(sr, occupied, ~us) & (occupied & ~square_bb(kto))))) + && (attackers_to(sr, occupied, ~us) & attackerCandidatesTheirs))) allCheck = false; } if (allCheck) @@ -1177,10 +1184,6 @@ bool Position::legal(Move m) const { } } - // Petrifying the king is illegal - if (var->petrifyOnCapture && capture(m) && type_of(moved_piece(m)) == KING) - return false; - // mutuallyImmuneTypes (diplomacy in Atomar)-- In no-check Atomic, kings can be beside each other, but in Atomar, this prevents them from actually taking. // Generalized to allow a custom set of pieces that can't capture a piece of the same type. if (capture(m) && @@ -1405,7 +1408,7 @@ bool Position::gives_check(Move m) const { // Is there a direct check? if (type_of(m) != PROMOTION && type_of(m) != PIECE_PROMOTION && type_of(m) != PIECE_DEMOTION && type_of(m) != CASTLING - && !(var->petrifyOnCapture && capture(m) && type_of(moved_piece(m)) != PAWN)) + && !((var->petrifyOnCaptureTypes & type_of(moved_piece(m))) && capture(m))) { PieceType pt = type_of(moved_piece(m)); if (pt == JANGGI_CANNON) @@ -1433,7 +1436,7 @@ bool Position::gives_check(Move m) const { return true; // Petrified piece can't give check - if (var->petrifyOnCapture && capture(m) && type_of(moved_piece(m)) != PAWN) + if ((var->petrifyOnCaptureTypes & type_of(moved_piece(m))) && capture(m)) return false; // Is there a check by special diagonal moves? @@ -1946,7 +1949,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { // Remove the blast pieces - if (captured && (blast_on_capture() || var->petrifyOnCapture)) + if (captured && (blast_on_capture() || var->petrifyOnCaptureTypes)) { std::memset(st->unpromotedBycatch, 0, sizeof(st->unpromotedBycatch)); st->demotedBycatch = st->promotedBycatch = 0; @@ -1956,7 +1959,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { blastImmune |= pieces(pt); }; Bitboard blast = blast_on_capture() ? ((attacks_bb(to) & ((pieces(WHITE) | pieces(BLACK)) ^ pieces(PAWN))) | to) - & (pieces() ^ blastImmune) : type_of(pc) != PAWN ? square_bb(to) : Bitboard(0); + & (pieces() ^ blastImmune) : var->petrifyOnCaptureTypes & type_of(pc) ? square_bb(to) : Bitboard(0); while (blast) { Square bsq = pop_lsb(blast); @@ -2018,7 +2021,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { } // Make a wall square where the piece was - if (bsq == to ? var->petrifyOnCapture : var->petrifyBlastPieces) + if (bsq == to ? bool(var->petrifyOnCaptureTypes & type_of(bpc)) : var->petrifyBlastPieces) { st->wallSquares |= bsq; byTypeBB[ALL_PIECES] |= bsq; @@ -2116,7 +2119,7 @@ void Position::undo_move(Move m) { byTypeBB[ALL_PIECES] ^= st->wallSquares ^ st->previous->wallSquares; // Add the blast pieces - if (st->capturedPiece && (blast_on_capture() || var->petrifyOnCapture)) + if (st->capturedPiece && (blast_on_capture() || var->petrifyOnCaptureTypes)) { Bitboard blast = attacks_bb(to) | to; while (blast) @@ -2435,6 +2438,10 @@ bool Position::see_ge(Move m, Value threshold) const { if (swap <= 0) return true; + // Petrification ends SEE + if (var->petrifyOnCaptureTypes & type_of(moved_piece(m)) && capture(m)) + return false; + Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) ^ to; Color stm = color_of(moved_piece(m)); Bitboard attackers = attackers_to(to, occupied); diff --git a/src/variant.cpp b/src/variant.cpp index e25d7ba0f..2fc1c9c49 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -460,6 +460,20 @@ namespace { v->extinctionPieceTypes = piece_set(ALL_PIECES); return v; } + // Petrified + // Sideways pawns + petrification on capture + // https://www.chess.com/variants/petrified + Variant* petrified_variant() { + Variant* v = pawnsideways_variant()->init(); + v->remove_piece(KING); + v->add_piece(COMMONER, 'k'); + v->castlingKingPiece[WHITE] = v->castlingKingPiece[BLACK] = COMMONER; + v->extinctionValue = -VALUE_MATE; + v->extinctionPieceTypes = piece_set(COMMONER); + v->extinctionPseudoRoyal = true; + v->petrifyOnCaptureTypes = piece_set(COMMONER) | QUEEN | ROOK | BISHOP | KNIGHT; + return v; + } // Atomic chess without checks (ICC rules) // https://www.chessclub.com/help/atomic Variant* nocheckatomic_variant() { @@ -493,6 +507,7 @@ namespace { #ifdef ALLVARS // Duck chess + // https://duckchess.com/ Variant* duck_variant() { Variant* v = chess_variant_base()->init(); v->remove_piece(KING); @@ -1805,6 +1820,7 @@ void VariantMap::init() { add("kinglet", kinglet_variant()); add("threekings", threekings_variant()); add("horde", horde_variant()); + add("petrified", petrified_variant()); add("nocheckatomic", nocheckatomic_variant()); add("atomic", atomic_variant()); add("atomar", atomar_variant()); @@ -2013,6 +2029,7 @@ Variant* Variant::conclude() { && !makpongRule && !connectN && !blastOnCapture + && !petrifyOnCaptureTypes && !capturesToHand && !twoBoards && !restrictedMobility diff --git a/src/variant.h b/src/variant.h index dd6036a3e..2a0269582 100644 --- a/src/variant.h +++ b/src/variant.h @@ -66,7 +66,7 @@ struct Variant { bool blastOnCapture = false; PieceSet blastImmuneTypes = NO_PIECE_SET; PieceSet mutuallyImmuneTypes = NO_PIECE_SET; - bool petrifyOnCapture = false; + PieceSet petrifyOnCaptureTypes = NO_PIECE_SET; bool petrifyBlastPieces = false; bool doubleStep = true; Bitboard doubleStepRegion[COLOR_NB] = {Rank2BB, Rank7BB}; diff --git a/src/variants.ini b/src/variants.ini index b5c035375..8afb5561e 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -169,7 +169,7 @@ # blastOnCapture: captures explode all adjacent non-pawn pieces (e.g., atomic chess) [bool] (default: false) # blastImmuneTypes: pieces completely immune to explosions (even at ground zero) [PieceSet] (default: none) # mutuallyImmuneTypes: pieces that can't capture another piece of same types (e.g., kings (commoners) in atomar) [PieceSet] (default: none) -# petrifyOnCapture: non-pawn pieces are turned into wall squares when capturing [bool] (default: false) +# petrifyOnCaptureTypes: defined pieces are turned into wall squares when capturing [PieceSet] (default: -) # petrifyBlastPieces: if petrify and blast combined, should pieces destroyed in the blast be petrified? [bool] (default: false) # doubleStep: enable pawn double step [bool] (default: true) # doubleStepRegionWhite: region where pawn double steps are allowed for white [Bitboard] (default: *2) @@ -1656,7 +1656,7 @@ startFen = lnsgkgsnl/1rci1uab1/p1p1p1p1p/9/9/9/P1P1P1P1P/1BAU1ICR1/LNSGKGSNL[-] pawn = - customPiece1 = p:fmWfceFifmnD pawnTypes = p -petrifyOnCapture = true +petrifyOnCaptureTypes = pnbrq enPassantRegion = - #https://en.wikipedia.org/wiki/Nim