Cfour-misere, per-color passing (#746)
authorRainRat <rainrat78@yahoo.ca>
Sun, 26 Nov 2023 21:30:48 +0000 (13:30 -0800)
committerGitHub <noreply@github.com>
Sun, 26 Nov 2023 21:30:48 +0000 (22:30 +0100)
src/movegen.cpp
src/parser.cpp
src/position.cpp
src/position.h
src/variant.cpp
src/variant.h
src/variants.ini
src/xboard.cpp

index b658619..43807bb 100644 (file)
@@ -441,7 +441,7 @@ namespace {
         }
 
         // Workaround for passing: Execute a non-move with any piece
-        if (pos.pass() && !pos.count<KING>(Us) && pos.pieces(Us))
+        if (pos.pass(Us) && !pos.count<KING>(Us) && pos.pieces(Us))
             *moveList++ = make<SPECIAL>(lsb(pos.pieces(Us)), lsb(pos.pieces(Us)));
     }
 
@@ -454,7 +454,7 @@ namespace {
             moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(b));
 
         // Passing move by king
-        if (pos.pass())
+        if (pos.pass(Us))
             *moveList++ = make<SPECIAL>(ksq, ksq);
 
         if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
index c925b2d..7535e68 100644 (file)
@@ -475,8 +475,14 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute("seirawanGating", v->seirawanGating);
     parse_attribute("cambodianMoves", v->cambodianMoves);
     parse_attribute("diagonalLines", v->diagonalLines);
-    parse_attribute("pass", v->pass);
-    parse_attribute("passOnStalemate", v->passOnStalemate);
+    parse_attribute("pass", v->pass[WHITE]);
+    parse_attribute("pass", v->pass[BLACK]);
+    parse_attribute("passWhite", v->pass[WHITE]);
+    parse_attribute("passBlack", v->pass[BLACK]);
+    parse_attribute("passOnStalemate", v->passOnStalemate[WHITE]);
+    parse_attribute("passOnStalemate", v->passOnStalemate[BLACK]);
+    parse_attribute("passOnStalemateWhite", v->passOnStalemate[WHITE]);
+    parse_attribute("passOnStalemateBlack", v->passOnStalemate[BLACK]);
     parse_attribute("makpongRule", v->makpongRule);
     parse_attribute("flyingGeneral", v->flyingGeneral);
     parse_attribute("soldierPromotionRank", v->soldierPromotionRank);
@@ -529,6 +535,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute("connectRegion1Black", v->connectRegion1[BLACK]);
     parse_attribute("connectRegion2Black", v->connectRegion2[BLACK]);
     parse_attribute("connectNxN", v->connectNxN);
+    parse_attribute("connectValue", v->connectValue);
     parse_attribute("materialCounting", v->materialCounting);
     parse_attribute("countingRule", v->countingRule);
     parse_attribute("castlingWins", v->castlingWins);
index 9b8ce39..a7ada05 100644 (file)
@@ -1092,7 +1092,7 @@ bool Position::legal(Move m) const {
       return false;
 
   // Illegal king passing move
-  if (pass_on_stalemate() && is_pass(m) && !checkers())
+  if (pass_on_stalemate(us) && is_pass(m) && !checkers())
   {
       for (const auto& move : MoveList<NON_EVASIONS>(*this))
           if (!is_pass(move) && legal(move))
@@ -1557,7 +1557,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   Piece captured = piece_on(type_of(m) == EN_PASSANT ? capture_square(to) : to);
   if (to == from)
   {
-      assert((type_of(m) == PROMOTION && sittuyin_promotion()) || (is_pass(m) && pass()));
+      assert((type_of(m) == PROMOTION && sittuyin_promotion()) || (is_pass(m) && pass(us)));
       captured = NO_PIECE;
   }
   st->capturedpromoted = is_promoted(to);
@@ -2126,7 +2126,7 @@ void Position::undo_move(Move m) {
 
   assert(type_of(m) == DROP || empty(from) || type_of(m) == CASTLING || is_gating(m)
          || (type_of(m) == PROMOTION && sittuyin_promotion())
-         || (is_pass(m) && pass()));
+         || (is_pass(m) && pass(us)));
   assert(type_of(st->capturedPiece) != KING);
 
   // Reset wall squares
@@ -2564,7 +2564,7 @@ bool Position::see_ge(Move m, Value threshold) const {
   return bool(res);
 }
 
-/// Position::is_optinal_game_end() tests whether the position may end the game by
+/// Position::is_optional_game_end() tests whether the position may end the game by
 /// 50-move rule, by repetition, or a variant rule that allows a player to claim a game result.
 
 bool Position::is_optional_game_end(Value& result, int ply, int countStarted) const {
@@ -2801,7 +2801,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
               b &= shift(d, b);
           if (b)
           {
-              result = mated_in(ply);
+              result = convert_mate_value(-var->connectValue, ply);
               return true;
           }
       }
@@ -2820,7 +2820,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
 
           if (newBitboard & target) {
               // A connection has been made
-              result = mated_in(ply);
+              result = convert_mate_value(-var->connectValue, ply);
               return true;
           }
 
@@ -2840,7 +2840,7 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
           connectors &= shift<SOUTH>(connectors) & shift<EAST>(connectors) & shift<SOUTH_EAST>(connectors);
       if (connectors)
       {
-          result = mated_in(ply);
+          result = convert_mate_value(-var->connectValue, ply);
           return true;
       }
   }
index 81c61dd..4ee9366 100644 (file)
@@ -182,8 +182,8 @@ public:
   bool seirawan_gating() const;
   bool cambodian_moves() const;
   Bitboard diagonal_lines() const;
-  bool pass() const;
-  bool pass_on_stalemate() const;
+  bool pass(Color c) const;
+  bool pass_on_stalemate(Color c) const;
   Bitboard promoted_soldiers(Color c) const;
   bool makpong() const;
   EnclosingRule flip_enclosed_pieces() const;
@@ -812,14 +812,14 @@ inline Bitboard Position::diagonal_lines() const {
   return var->diagonalLines;
 }
 
-inline bool Position::pass() const {
+inline bool Position::pass(Color c) const {
   assert(var != nullptr);
-  return var->pass || var->passOnStalemate;
+  return var->pass[c] || var->passOnStalemate[c];
 }
 
-inline bool Position::pass_on_stalemate() const {
+inline bool Position::pass_on_stalemate(Color c) const {
   assert(var != nullptr);
-  return var->passOnStalemate;
+  return var->passOnStalemate[c];
 }
 
 inline Bitboard Position::promoted_soldiers(Color c) const {
index 8a42468..cd565ba 100644 (file)
@@ -1136,7 +1136,8 @@ namespace {
         v->immobilityIllegal = false;
         v->stalemateValue = -VALUE_MATE;
         v->stalematePieceCount = true;
-        v->passOnStalemate = true;
+        v->passOnStalemate[WHITE] = true;
+        v->passOnStalemate[BLACK] = true;
         v->enclosingDrop = ATAXX;
         v->flipEnclosedPieces = ATAXX;
         v->materialCounting = UNWEIGHTED_MATERIAL;
@@ -1160,7 +1161,8 @@ namespace {
         v->immobilityIllegal = false;
         v->stalemateValue = -VALUE_MATE;
         v->stalematePieceCount = true;
-        v->passOnStalemate = false;
+        v->passOnStalemate[WHITE] = false;
+        v->passOnStalemate[BLACK] = false;
         v->enclosingDrop = REVERSI;
         v->enclosingDropStart = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5);
         v->flipEnclosedPieces = REVERSI;
@@ -1172,7 +1174,8 @@ namespace {
     Variant* flipello_variant() {
         Variant* v = flipersi_variant()->init();
         v->startFen = "8/8/8/3pP3/3Pp3/8/8/8[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppppppppppp] w 0 1";
-        v->passOnStalemate = true;
+        v->passOnStalemate[WHITE] = true;
+        v->passOnStalemate[BLACK] = true;
         return v;
     }
     // Minixiangqi
@@ -1742,7 +1745,8 @@ namespace {
         v->materialCounting = JANGGI_MATERIAL;
         v->diagonalLines = make_bitboard(SQ_D1, SQ_F1, SQ_E2, SQ_D3, SQ_F3,
                                          SQ_D8, SQ_F8, SQ_E9, SQ_D10, SQ_F10);
-        v->pass = true;
+        v->pass[WHITE] = true;
+        v->pass[BLACK] = true;
         v->nFoldValue = VALUE_DRAW;
         v->perpetualCheckIllegal = true;
         return v;
index 49bc544..b9174ad 100644 (file)
@@ -111,8 +111,8 @@ struct Variant {
   bool seirawanGating = false;
   bool cambodianMoves = false;
   Bitboard diagonalLines = 0;
-  bool pass = false;
-  bool passOnStalemate = false;
+  bool pass[COLOR_NB] = {false, false};
+  bool passOnStalemate[COLOR_NB] = {false, false};
   bool makpongRule = false;
   bool flyingGeneral = false;
   Rank soldierPromotionRank = RANK_1;
@@ -155,6 +155,7 @@ struct Variant {
   Bitboard connectRegion1[COLOR_NB] = {};
   Bitboard connectRegion2[COLOR_NB] = {};
   int connectNxN = 0;
+  Value connectValue = VALUE_MATE;
   MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
   CountingRule countingRule = NO_COUNTING;
   CastlingRights castlingWins = NO_CASTLING;
index b7dd011..6b3ea74 100644 (file)
 # cambodianMoves: enable special moves of cambodian chess, requires "gating = true" [bool] (default: false)
 # diagonalLines: enable special moves along diagonal for specific squares (Janggi) [Bitboard]
 # pass: allow passing [bool] (default: false)
+# passWhite: allow passing for white [bool] (default: false)
+# passBlack: allow passing for black [bool] (default: false)
 # passOnStalemate: allow passing in case of stalemate [bool] (default: false)
+# passOnStalemateWhite: allow passing in case of stalemate for white [bool] (default: false)
+# passOnStalemateBlack: allow passing in case of stalemate for black [bool] (default: false)
 # makpongRule: the king may not move away from check [bool] (default: false)
 # flyingGeneral: disallow general face-off like in xiangqi [bool] (default: false)
 # soldierPromotionRank: restrict soldier to shogi pawn movements until reaching n-th rank [Rank] (default: 1)
 # connectRegion1Black: "
 # connectRegion2Black: "
 # connectNxN: connect a tight NxN square for win [int] (default: 0)
+# connectValue: result in case of connect [Value] (default: win)
 # 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. [CastlingRights] (default: -)
@@ -1903,3 +1908,6 @@ maxRank = 7
 startFen = 7/7/7/7/7/7/7[PPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppp] w - - 0 1
 enclosingDrop = anyside
 
+#http://gamescrafters.berkeley.edu/games.php?game=connect4
+[cfour-misere:cfour]
+connectValue = loss
index 482b5e4..09228ed 100644 (file)
@@ -308,7 +308,7 @@ void StateMachine::process_command(std::string token, std::istringstream& is) {
       std::getline(is >> std::ws, fen);
       // Check if setboard actually indicates a passing move
       // to avoid unnecessarily clearing the move history
-      if (pos.pass())
+      if (pos.pass(~pos.side_to_move()))
       {
           StateInfo st;
           Position p;