From 8e3fe58f4401245b02e4a8be8726f08a503d5959 Mon Sep 17 00:00:00 2001 From: RainRat Date: Sun, 10 Sep 2023 04:23:42 -0700 Subject: [PATCH] add Castle Chess (#717) --- src/parser.cpp | 3 ++- src/position.cpp | 30 ++++++++++++++++++++++++++++++ src/variant.cpp | 9 +++++++++ src/variant.h | 2 ++ src/variants.ini | 5 +++++ 5 files changed, 48 insertions(+), 1 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 47fd5d2..df0ce18 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -472,7 +472,8 @@ Variant* VariantParser::parse(Variant* v) { parse_attribute("connectDiagonal", v->connectDiagonal); parse_attribute("materialCounting", v->materialCounting); parse_attribute("countingRule", v->countingRule); - + parse_attribute("castlingWins", v->castlingWins); + // Report invalid options if (DoCheck) { diff --git a/src/position.cpp b/src/position.cpp index de08457..8f7185c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -2736,6 +2736,36 @@ bool Position::is_immediate_game_end(Value& result, int ply) const { return true; } } + + // Castle chess + if (var->castlingWinConditions) { + if (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) + { + 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; + } + } + // nCheck if (check_counting() && checks_remaining(~sideToMove) == 0) { diff --git a/src/variant.cpp b/src/variant.cpp index e25d7ba..6162a4b 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -2041,6 +2041,15 @@ 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 94f67b3..449407e 100644 --- a/src/variant.h +++ b/src/variant.h @@ -157,6 +157,7 @@ struct Variant { bool connectDiagonal = true; MaterialCounting materialCounting = NO_MATERIAL_COUNTING; CountingRule countingRule = NO_COUNTING; + std::string castlingWins = ""; // Derived properties bool fastAttacks = true; @@ -172,6 +173,7 @@ 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 86309a5..8e7881a 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -266,6 +266,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: "") ################################################ ### Example for minishogi configuration that would be equivalent to the built-in variant: @@ -1719,5 +1720,9 @@ doubleStepRegionBlack = *8 pieceDrops = true castlingRank = 2 +#https://www.chessvariants.com/winning.dir/castle.html +[castle:chess] +castlingWins = q + [opposite-castling:chess] oppositeCastling = true -- 1.7.0.4