add Castle Chess (#717)
authorRainRat <rainrat78@yahoo.ca>
Sun, 10 Sep 2023 11:23:42 +0000 (04:23 -0700)
committerGitHub <noreply@github.com>
Sun, 10 Sep 2023 11:23:42 +0000 (13:23 +0200)
src/parser.cpp
src/position.cpp
src/variant.cpp
src/variant.h
src/variants.ini

index 47fd5d2..df0ce18 100644 (file)
@@ -472,7 +472,8 @@ Variant* VariantParser<DoCheck>::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)
     {
index de08457..8f7185c 100644 (file)
@@ -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<CastlingRights>((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)
   {
index e25d7ba..6162a4b 100644 (file)
@@ -2041,6 +2041,15 @@ Variant* Variant::conclude() {
         connect_directions.push_back(SOUTH_EAST);
     }
 
+    for (char c : castlingWins) {
+        switch (c) {
+            case 'K': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | WHITE_OO); break;
+            case 'Q': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | WHITE_OOO); break;
+            case 'k': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | BLACK_OO); break;
+            case 'q': castlingWinConditions = static_cast<CastlingRights>(castlingWinConditions | BLACK_OOO); break;
+        }
+    }
+
     return this;
 }
 
index 94f67b3..449407e 100644 (file)
@@ -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<Direction> 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
index 86309a5..8e7881a 100644 (file)
 # 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