From: Fabian Fichter Date: Sun, 10 Sep 2023 12:10:44 +0000 (+0200) Subject: Add CastlingRights as dedicated config type X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=5f986594105aa766f7d085fb744c9e5fa209e99a;p=fairystockfish.git Add CastlingRights as dedicated config type No functional change. --- diff --git a/src/parser.cpp b/src/parser.cpp index df0ce18..078c338 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -124,6 +124,27 @@ namespace { return !ss.fail(); } + template <> bool set(const std::string& value, CastlingRights& target) { + char c; + CastlingRights castlingRight; + std::stringstream ss(value); + target = NO_CASTLING; + bool valid = true; + while (ss >> c && c != '-') + { + castlingRight = c == 'K' ? WHITE_OO + : c == 'Q' ? WHITE_OOO + : c == 'k' ? BLACK_OO + : c == 'q' ? BLACK_OOO + : NO_CASTLING; + if (castlingRight) + target = CastlingRights(target | castlingRight); + else + valid = false; + } + return valid; + } + template void set(PieceType pt, T& target) { target.insert(pt); } @@ -158,6 +179,7 @@ template bool VariantParser::parse_attribute(co : std::is_same() ? "ChasingRule" : std::is_same() ? "EnclosingRule" : std::is_same() ? "Bitboard" + : std::is_same() ? "CastlingRights" : typeid(T).name(); std::cerr << key << " - Invalid value " << it->second << " for type " << typeName << std::endl; } diff --git a/src/position.cpp b/src/position.cpp index 8f7185c..a55d50b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -2738,32 +2738,28 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { } // Castle chess - if (var->castlingWinConditions) { - if (type_of(st->move) == CASTLING) + if (var->castlingWins) + { + if (st->pliesFromNull > 0 && type_of(st->move) == CASTLING) { - //check for victory first, because castling also removes castling rights. - CastlingRights justCastled = static_cast((sideToMove == BLACK ? WHITE_OOO : BLACK_OOO) - >> ((from_sq(st->move) < to_sq(st->move)) ? 1 : 0)); - if (var->castlingWinConditions & justCastled) + // check for victory first, because castling also removes castling rights. + CastlingRights justCastled = ~sideToMove & ((from_sq(st->move) < to_sq(st->move)) ? KING_SIDE : QUEEN_SIDE); + if (var->castlingWins & justCastled) { result = mated_in(ply); return true; } } - if ((var->castlingWinConditions & BLACK_CASTLING) && (!(var->castlingWinConditions & BLACK_CASTLING & st->castlingRights))) - { - //black permanently losing castling rights. either through moving a castling piece, - //or having their rook captured. Either way, black lost. - result = sideToMove == WHITE ? mate_in(ply) : mated_in(ply); - return true; - } - if ((var->castlingWinConditions & WHITE_CASTLING) && (!(var->castlingWinConditions & WHITE_CASTLING & st->castlingRights))) - { - //white permanently losing castling rights. either through moving a castling piece, - //or having their rook captured. Either way, white lost. - result = sideToMove == BLACK ? mate_in(ply) : mated_in(ply); - return true; - } + // We check the opponent side first, because a rook capturing a rook could remove both sides castling rights, + // which should likely be seen as losing, analogous to extinction rules. + for (Color c : { ~sideToMove, sideToMove }) + if ((c & var->castlingWins) && !(c & var->castlingWins & st->castlingRights)) + { + // player permanently losing castling rights. either through moving a castling piece, + // or having their rook captured. + result = c == sideToMove ? mated_in(ply) : mate_in(ply); + return true; + } } // nCheck diff --git a/src/variant.cpp b/src/variant.cpp index 6162a4b..e25d7ba 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -2041,15 +2041,6 @@ Variant* Variant::conclude() { connect_directions.push_back(SOUTH_EAST); } - for (char c : castlingWins) { - switch (c) { - case 'K': castlingWinConditions = static_cast(castlingWinConditions | WHITE_OO); break; - case 'Q': castlingWinConditions = static_cast(castlingWinConditions | WHITE_OOO); break; - case 'k': castlingWinConditions = static_cast(castlingWinConditions | BLACK_OO); break; - case 'q': castlingWinConditions = static_cast(castlingWinConditions | BLACK_OOO); break; - } - } - return this; } diff --git a/src/variant.h b/src/variant.h index 449407e..dd6036a 100644 --- a/src/variant.h +++ b/src/variant.h @@ -157,7 +157,7 @@ struct Variant { bool connectDiagonal = true; MaterialCounting materialCounting = NO_MATERIAL_COUNTING; CountingRule countingRule = NO_COUNTING; - std::string castlingWins = ""; + CastlingRights castlingWins = NO_CASTLING; // Derived properties bool fastAttacks = true; @@ -173,7 +173,6 @@ struct Variant { bool endgameEval = false; bool shogiStylePromotions = false; std::vector connect_directions; - CastlingRights castlingWinConditions = NO_CASTLING; void add_piece(PieceType pt, char c, std::string betza = "", char c2 = ' ') { // Avoid ambiguous definition by removing existing piece with same letter diff --git a/src/variants.ini b/src/variants.ini index 8e7881a..7d0b36f 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -124,6 +124,7 @@ # [int]: any natural number [0, 1, ...] # [PieceType]: a piece type [letters defined for pieces, e.g., p] # [PieceSet]: multiple piece types [letters defined for pieces, e.g., nbrq] +# [CastlingRights]: set of castling rights [letters for castling rights as in FEN, e.g., KQkq] # [Bitboard]: list of squares [e.g., d4 e4 d5 e5]. * can be used as wildcard for files (e.g., *1 is the first rank) # [Value]: game result for the side to move [win, loss, draw] # [MaterialCounting]: material counting rules for adjudication [janggi, unweighted, whitedrawodds, blackdrawodds, none] @@ -266,7 +267,7 @@ # connectDiagonal: connectN looks at Diagonal rows [bool] (default: true) # materialCounting: enable material counting rules [MaterialCounting] (default: none) # countingRule: enable counting rules [CountingRule] (default: none) -# castlingWins: Specified castling moves are win conditions. Losing these rights is losing. (ie. KQkq) [string] (default: "") +# castlingWins: Specified castling moves are win conditions. Losing these rights is losing. [CastlingRights] (default: -) ################################################ ### Example for minishogi configuration that would be equivalent to the built-in variant: