add Duck region mask. add forward/checkers (#705)
authorRainRat <rainrat78@yahoo.ca>
Wed, 6 Sep 2023 07:34:28 +0000 (00:34 -0700)
committerGitHub <noreply@github.com>
Wed, 6 Sep 2023 07:34:28 +0000 (09:34 +0200)
src/apiutil.h
src/movegen.cpp
src/parser.cpp
src/position.cpp
src/position.h
src/search.cpp
src/uci.cpp
src/variant.cpp
src/variant.h
src/variants.ini

index ca5858e..0794abc 100644 (file)
@@ -346,7 +346,7 @@ inline const std::string move_to_san(Position& pos, Move m, Notation n) {
     }
 
     // Wall square
-    if (pos.wall_gating())
+    if (pos.walling())
         san += "," + square(pos, gating_square(m), n);
 
     // Check and checkmate
index b33d986..0c14dd7 100644 (file)
@@ -29,7 +29,7 @@ namespace {
   ExtMove* make_move_and_gating(const Position& pos, ExtMove* moveList, Color us, Square from, Square to, PieceType pt = NO_PIECE_TYPE) {
 
     // Wall placing moves
-    if (pos.wall_gating())
+    if (pos.walling())
     {
         Bitboard b = pos.board_bb() & ~((pos.pieces() ^ from) | to);
         if (T == CASTLING)
@@ -41,11 +41,11 @@ namespace {
         }
         if (T == EN_PASSANT)
             b ^= pos.capture_square(to);
-        if (pos.variant()->arrowGating)
+        if (pos.variant()->arrowWalling)
             b &= moves_bb(us, type_of(pos.piece_on(from)), to, pos.pieces() ^ from);
-        if (pos.variant()->staticGating)
-            b &= pos.variant()->staticGatingRegion;
-        if (pos.variant()->pastGating)
+        if ((pos.variant()->staticWalling)||(pos.variant()->duckWalling))
+            b &= pos.variant()->wallingRegion[us];
+        if (pos.variant()->pastWalling)
             b &= square_bb(from);
 
         while (b)
index 348f17f..4b07440 100644 (file)
@@ -410,11 +410,14 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute("dropNoDoubledCount", v->dropNoDoubledCount);
     parse_attribute("immobilityIllegal", v->immobilityIllegal);
     parse_attribute("gating", v->gating);
-    parse_attribute("arrowGating", v->arrowGating);
-    parse_attribute("duckGating", v->duckGating);
-    parse_attribute("staticGating", v->staticGating);
-    parse_attribute("pastGating", v->pastGating);
-    parse_attribute("staticGatingRegion", v->staticGatingRegion);
+    parse_attribute("arrowWalling", v->arrowWalling);
+    parse_attribute("duckWalling", v->duckWalling);
+    parse_attribute("wallingRegionWhite", v->wallingRegion[WHITE]);
+    parse_attribute("wallingRegionBlack", v->wallingRegion[BLACK]);
+    parse_attribute("wallingRegion", v->wallingRegion[WHITE]);
+    parse_attribute("wallingRegion", v->wallingRegion[BLACK]);
+    parse_attribute("staticWalling", v->staticWalling);
+    parse_attribute("pastWalling", v->pastWalling);
     parse_attribute("seirawanGating", v->seirawanGating);
     parse_attribute("cambodianMoves", v->cambodianMoves);
     parse_attribute("diagonalLines", v->diagonalLines);
@@ -525,8 +528,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
             std::cerr << "Inconsistent settings: castlingQueensideFile > castlingKingsideFile." << std::endl;
 
         // Check for limitations
-        if (v->pieceDrops && (v->arrowGating || v->duckGating || v->staticGating || v->pastGating))
-            std::cerr << "pieceDrops and arrowGating/duckGating are incompatible." << std::endl;
+        if (v->pieceDrops && (v->arrowWalling || v->duckWalling || v->staticWalling || v->pastWalling))
+            std::cerr << "pieceDrops and arrowWalling/duckWalling are incompatible." << std::endl;
 
         // Options incompatible with royal kings
         if (v->pieceTypes & KING)
@@ -535,8 +538,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
                 std::cerr << "Can not use kings with blastOnCapture." << std::endl;
             if (v->flipEnclosedPieces)
                 std::cerr << "Can not use kings with flipEnclosedPieces." << std::endl;
-            if (v->duckGating)
-                std::cerr << "Can not use kings with duckGating." << std::endl;
+            if (v->duckWalling)
+                std::cerr << "Can not use kings with duckWalling." << std::endl;
             // We can not fully check support for custom king movements at this point,
             // since custom pieces are only initialized on loading of the variant.
             // We will assume this is valid, but it might cause problems later if it's not.
index 1b8ae90..a87ce1d 100644 (file)
@@ -1099,9 +1099,9 @@ bool Position::legal(Move m) const {
   {
       Square kto = to;
       Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces());
-      if (var->duckGating)
+      if (var->duckWalling)
           occupied ^= st->wallSquares;
-      if (wall_gating() || is_gating(m))
+      if (walling() || is_gating(m))
           occupied |= gating_square(m);
       if (type_of(m) == CASTLING)
       {
@@ -1296,15 +1296,15 @@ bool Position::pseudo_legal(const Move m) const {
                         : MoveList<NON_EVASIONS>(*this).contains(m);
 
   // Illegal wall square placement
-  if (wall_gating() && !((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
+  if (walling() && !((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
       return false;
-  if (var->arrowGating && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
+  if (var->arrowWalling && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
       return false;
-  if (var->pastGating && (from != gating_square(m)))
+  if (var->pastWalling && (from != gating_square(m)))
       return false;
-  if (var->staticGating && !(var->staticGatingRegion & gating_square(m)))
+  if ((var->staticWalling || var->duckWalling) && !(var->wallingRegion[us] & gating_square(m)))
       return false;
-  
+
   // Handle the case where a mandatory piece promotion/demotion is not taken
   if (    mandatory_piece_promotion()
       && (is_promoted(from) ? piece_demotion() : promoted_piece_type(type_of(pc)) != NO_PIECE_TYPE)
@@ -1803,7 +1803,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
       {
           if (   (var->enPassantRegion & (to - pawn_push(us)))
               && ((pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN))
-              && !(wall_gating() && gating_square(m) == to - pawn_push(us)))
+              && !(walling() && gating_square(m) == to - pawn_push(us)))
           {
               st->epSquares |= to - pawn_push(us);
               k ^= Zobrist::enpassant[file_of(to)];
@@ -1811,7 +1811,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
           if (   std::abs(int(to) - int(from)) == 3 * NORTH
               && (var->enPassantRegion & (to - 2 * pawn_push(us)))
               && ((pawn_attacks_bb(us, to - 2 * pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN))
-              && !(wall_gating() && gating_square(m) == to - 2 * pawn_push(us)))
+              && !(walling() && gating_square(m) == to - 2 * pawn_push(us)))
           {
               st->epSquares |= to - 2 * pawn_push(us);
               k ^= Zobrist::enpassant[file_of(to)];
@@ -2016,10 +2016,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   }
 
   // Add gated wall square
-  if (wall_gating())
+  if (walling())
   {
-      // Reset wall squares for duck gating
-      if (var->duckGating)
+      // Reset wall squares for duck walling
+      if (var->duckWalling)
       {
           Bitboard b = st->previous->wallSquares;
           byTypeBB[ALL_PIECES] ^= b;
@@ -2457,7 +2457,7 @@ bool Position::see_ge(Move m, Value threshold) const {
           stmAttackers &= ~blockers_for_king(stm);
 
       // Ignore distant sliders
-      if (var->duckGating)
+      if (var->duckWalling)
           stmAttackers &= attacks_bb<KING>(to) | ~(pieces(BISHOP, ROOK) | pieces(QUEEN));
 
       if (!stmAttackers)
@@ -2924,7 +2924,7 @@ bool Position::has_game_cycle(int ply) const {
 
   int end = captures_to_hand() ? st->pliesFromNull : std::min(st->rule50, st->pliesFromNull);
 
-  if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal || var->duckGating)
+  if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal || var->duckWalling)
     return false;
 
   Key originalKey = st->key;
index fcdd6ca..2279135 100644 (file)
@@ -178,7 +178,7 @@ public:
   PieceType drop_no_doubled() const;
   bool immobility_illegal() const;
   bool gating() const;
-  bool wall_gating() const;
+  bool walling() const;
   bool seirawan_gating() const;
   bool cambodian_moves() const;
   Bitboard diagonal_lines() const;
@@ -753,9 +753,9 @@ inline bool Position::gating() const {
   return var->gating;
 }
 
-inline bool Position::wall_gating() const {
+inline bool Position::walling() const {
   assert(var != nullptr);
-  return var->arrowGating || var->duckGating || var->staticGating || var->pastGating;
+  return var->arrowWalling || var->duckWalling || var->staticWalling || var->pastWalling;
 }
 
 inline bool Position::seirawan_gating() const {
index 38d72f5..2502fcc 100644 (file)
@@ -80,7 +80,7 @@ namespace {
   }
 
   int futility_move_count(bool improving, Depth depth, const Position& pos) {
-    return (3 + depth * depth * (1 + pos.wall_gating()) + 2 * pos.blast_on_capture()) / (2 - improving + pos.blast_on_capture());
+    return (3 + depth * depth * (1 + pos.walling()) + 2 * pos.blast_on_capture()) / (2 - improving + pos.blast_on_capture());
   }
 
   // History and stats update bonus, based on depth
@@ -281,7 +281,7 @@ void MainThread::search() {
       if (!Limits.infinite && !ponder && rootMoves[0].pv[0] != MOVE_NONE && !Threads.abort.exchange(true))
       {
           std::string move = UCI::move(rootPos, bestMove);
-          if (rootPos.wall_gating())
+          if (rootPos.walling())
           {
               sync_cout << "move " << move.substr(0, move.find(",")) << "," << sync_endl;
               sync_cout << "move " << move.substr(move.find(",") + 1) << sync_endl;
@@ -800,7 +800,7 @@ namespace {
             {
                 int penalty = -stat_bonus(depth);
                 thisThread->mainHistory[us][from_to(ttMove)] << penalty;
-                if (pos.wall_gating())
+                if (pos.walling())
                     thisThread->gateHistory[us][gating_square(ttMove)] << penalty;
                 update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty);
             }
@@ -1185,7 +1185,7 @@ moves_loop: // When in check, search starts from here
                   continue;
 
               // Prune moves with negative SEE (~20 Elo)
-              if (!pos.variant()->duckGating && !pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18) + 10 * !!pos.flag_region(pos.side_to_move())) * lmrDepth * lmrDepth)))
+              if (!pos.variant()->duckWalling && !pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18) + 10 * !!pos.flag_region(pos.side_to_move())) * lmrDepth * lmrDepth)))
                   continue;
           }
       }
@@ -1823,9 +1823,9 @@ moves_loop: // When in check, search starts from here
         // Decrease stats for all non-best quiet moves
         for (int i = 0; i < quietCount; ++i)
         {
-            if (!(pos.wall_gating() && from_to(quietsSearched[i]) == from_to(bestMove)))
+            if (!(pos.walling() && from_to(quietsSearched[i]) == from_to(bestMove)))
                 thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bonus2;
-            if (pos.wall_gating())
+            if (pos.walling())
                 thisThread->gateHistory[us][gating_square(quietsSearched[i])] << -bonus2;
             update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]), to_sq(quietsSearched[i]), -bonus2);
         }
@@ -1834,7 +1834,7 @@ moves_loop: // When in check, search starts from here
     {
         // Increase stats for the best move in case it was a capture move
         captureHistory[moved_piece][to_sq(bestMove)][captured] << bonus1;
-        if (pos.wall_gating())
+        if (pos.walling())
             thisThread->gateHistory[us][gating_square(bestMove)] << bonus1;
     }
 
@@ -1849,9 +1849,9 @@ moves_loop: // When in check, search starts from here
     {
         moved_piece = pos.moved_piece(capturesSearched[i]);
         captured = type_of(pos.piece_on(to_sq(capturesSearched[i])));
-        if (!(pos.wall_gating() && from_to(capturesSearched[i]) == from_to(bestMove)))
+        if (!(pos.walling() && from_to(capturesSearched[i]) == from_to(bestMove)))
             captureHistory[moved_piece][to_sq(capturesSearched[i])][captured] << -bonus1;
-        if (pos.wall_gating())
+        if (pos.walling())
             thisThread->gateHistory[us][gating_square(capturesSearched[i])] << -bonus1;
     }
   }
@@ -1887,7 +1887,7 @@ moves_loop: // When in check, search starts from here
     Color us = pos.side_to_move();
     Thread* thisThread = pos.this_thread();
     thisThread->mainHistory[us][from_to(move)] << bonus;
-    if (pos.wall_gating())
+    if (pos.walling())
         thisThread->gateHistory[us][gating_square(move)] << bonus;
     update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus);
 
index 9902afd..584977a 100644 (file)
@@ -535,7 +535,7 @@ string UCI::move(const Position& pos, Move m) {
                                     : UCI::square(pos, from)) + UCI::square(pos, to);
 
   // Wall square
-  if (pos.wall_gating() && CurrentProtocol == XBOARD)
+  if (pos.walling() && CurrentProtocol == XBOARD)
       move += "," + UCI::square(pos, to) + UCI::square(pos, gating_square(m));
 
   if (type_of(m) == PROMOTION)
@@ -552,7 +552,7 @@ string UCI::move(const Position& pos, Move m) {
   }
 
   // Wall square
-  if (pos.wall_gating() && CurrentProtocol != XBOARD)
+  if (pos.walling() && CurrentProtocol != XBOARD)
       move += "," + UCI::square(pos, to) + UCI::square(pos, gating_square(m));
 
   return move;
index a0ce815..311651c 100644 (file)
@@ -500,7 +500,7 @@ namespace {
         v->castlingKingPiece[WHITE] = v->castlingKingPiece[BLACK] = COMMONER;
         v->extinctionValue = -VALUE_MATE;
         v->extinctionPieceTypes = piece_set(COMMONER);
-        v->duckGating = true;
+        v->duckWalling = true;
         v->stalemateValue = VALUE_MATE;
         return v;
     }
@@ -512,10 +512,10 @@ namespace {
         v->maxFile = FILE_F;
         v->reset_pieces();
         v->add_piece(CUSTOM_PIECE_1, 'p', "mK"); //move as a King, but can't capture
-        v->startFen = "2p3/6/6/6/6/6/6/3P2 w - - 0 1";
+        v->startFen = "3p2/6/6/6/6/6/6/2P3 w - - 0 1";
         v->stalemateValue = -VALUE_MATE;
-        v->staticGating = true;
-        v->staticGatingRegion = AllSquares ^ make_bitboard(SQ_C1, SQ_D8);
+        v->staticWalling = true;
+        v->wallingRegion[WHITE] = v->wallingRegion[BLACK] = AllSquares ^ make_bitboard(SQ_C1, SQ_D8);
         return v;
     }
 
@@ -524,7 +524,7 @@ namespace {
         v->maxRank = RANK_7;
         v->maxFile = FILE_G;
         v->startFen = "3p3/7/7/7/7/7/3P3 w - - 0 1";
-        v->staticGatingRegion = AllSquares ^ make_bitboard(SQ_D1, SQ_D7);
+        v->wallingRegion[WHITE] = v->wallingRegion[BLACK] = AllSquares ^ make_bitboard(SQ_D1, SQ_D7);
         return v;
     }
 
@@ -536,7 +536,7 @@ namespace {
         v->add_piece(CUSTOM_PIECE_1, 'p', "mK"); //move as a King, but can't capture
         v->startFen = "6p/7/7/7/7/7/P6 w - - 0 1";
         v->stalemateValue = -VALUE_MATE;
-        v->pastGating = true;
+        v->pastWalling = true;
         return v;
     }
 
@@ -547,7 +547,7 @@ namespace {
         v->add_piece(CUSTOM_PIECE_1, 'n', "mN"); //move as a Knight, but can't capture
         v->startFen = "8/8/8/4n3/3N4/8/8/8 w - - 0 1";
         v->stalemateValue = -VALUE_MATE;
-        v->pastGating = true;
+        v->pastWalling = true;
         return v;
     }
 
@@ -1653,7 +1653,7 @@ namespace {
         v->add_piece(CUSTOM_PIECE_1, 'q', "mQ");
         v->startFen = "3q2q3/10/10/q8q/10/10/Q8Q/10/10/3Q2Q3 w - - 0 1";
         v->stalemateValue = -VALUE_MATE;
-        v->arrowGating = true;
+        v->arrowWalling = true;
         return v;
     }
 #endif
index 0492dcc..37de420 100644 (file)
@@ -106,11 +106,11 @@ struct Variant {
   int dropNoDoubledCount = 1;
   bool immobilityIllegal = false;
   bool gating = false;
-  bool arrowGating = false;
-  bool duckGating = false;
-  bool staticGating = false;
-  bool pastGating = false;
-  Bitboard staticGatingRegion = AllSquares;
+  bool arrowWalling = false;
+  bool duckWalling = false;
+  bool staticWalling = false;
+  bool pastWalling = false;
+  Bitboard wallingRegion[COLOR_NB] = {AllSquares, AllSquares};
   bool seirawanGating = false;
   bool cambodianMoves = false;
   Bitboard diagonalLines = 0;
index 60c701c..71cb8d2 100644 (file)
 # dropNoDoubledCount: specifies the count of already existing pieces for dropNoDoubled [int] (default: 1)
 # immobilityIllegal: pieces may not move to squares where they can never move from [bool] (default: false)
 # gating: maintain squares on backrank with extra rights in castling field of FEN [bool] (default: false)
-# arrowGating: gating of wall squares in Game of the Amazons style [bool] (default: false)
-# duckGating: gating of a wall square in Duck chess style [bool] (default: false)
-# staticGating: gating of wall squares in Isolation style [bool] (default: false)
-# staticGatingRegion: mask where wall squares can be placed [Bitboard] (default: all squares)
-# pastGating: gating of previous square [bool] (default: false)
+# arrowWalling: walling squares in Game of the Amazons style [bool] (default: false)
+# duckWalling: walling square in Duck chess style [bool] (default: false)
+# staticWalling: walling squares in Isolation style [bool] (default: false)
+# wallingRegionWhite: mask where wall squares (including duck) can be placed by white [Bitboard] (default: all squares)
+# wallingRegionBlack: mask where wall squares (including duck) can be placed by black [Bitboard] (default: all squares)
+# pastWalling: walling of previous square in Snailtrail style [bool] (default: false)
 # seirawanGating: allow gating of pieces in hand like in S-Chess, requires "gating = true" [bool] (default: false)
 # cambodianMoves: enable special moves of cambodian chess, requires "gating = true" [bool] (default: false)
 # diagonalLines: enable special moves along diagonal for specific squares (Janggi) [Bitboard]
@@ -1345,9 +1346,27 @@ pieceToCharTable = P...Q..AH..ECTDY....LKp...q..ah..ectdy....lk
 # Atomic + duck chess hybrid.
 # Playable as a custom variant in chess.com
 [atomicduck:atomic]
-duckGating = true
+duckWalling = true
 stalemateValue = win
 
+#https://www.chessvariants.com/diffmove.dir/checkers.html
+[forward:chess]
+pieceToCharTable = PNBRQGE......S.F..LKpnbrqge......s.f..lk
+#pieces move only forward. Not even sideways, so no castling.
+castling = false
+#I tried to pick letters that would remind people of the full piece.
+startFen = lesfgsel/pppppppp/8/8/8/8/PPPPPPPP/LESFGSEL w KQkq - 0 1
+lance = l
+customPiece1 = g:fFfW
+customPiece2 = e:ffNfsN
+customPiece3 = s:fB
+customPiece4 = f:fBfR
+promotedPieceType = l:r e:n s:b f:q g:k
+#since the king changes forms, should be an extinction variant
+extinctionValue = loss
+extinctionPieceTypes = kg
+extinctionPseudoRoyal = true
+
 [kono]
 maxRank = 5
 maxFile = e