Add Cfour-anyside, Symphony, Teeko (#731)
authorRainRat <rainrat78@yahoo.ca>
Tue, 24 Oct 2023 20:03:24 +0000 (13:03 -0700)
committerGitHub <noreply@github.com>
Tue, 24 Oct 2023 20:03:24 +0000 (22:03 +0200)
src/parser.cpp
src/position.cpp
src/position.h
src/types.h
src/variant.h
src/variants.ini

index 48b8cc9..1c4b4fa 100644 (file)
@@ -107,8 +107,10 @@ namespace {
                 : value == "ataxx" ? ATAXX
                 : value == "quadwrangle" ? QUADWRANGLE
                 : value == "snort" ? SNORT
+                : value == "anyside" ? ANYSIDE
+                : value == "top" ? TOP
                 : NO_ENCLOSING;
-        return value == "reversi" || value == "ataxx" || value == "quadwrangle" || value =="snort" || value == "none";
+        return value == "reversi" || value == "ataxx" || value == "quadwrangle" || value =="snort" || value =="anyside" || value =="top" || value == "none";
     }
 
     template <> bool set(const std::string& value, WallingRule& target) {
@@ -327,6 +329,10 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute<false>("castlingRookPiece", v->castlingRookPieces[WHITE], v->pieceToChar);
     parse_attribute<false>("castlingRookPiece", v->castlingRookPieces[BLACK], v->pieceToChar);
 
+    bool dropOnTop = false;
+    parse_attribute<false>("dropOnTop", dropOnTop);
+    if (dropOnTop) v->enclosingDrop=TOP;
+
     // Parse aliases
     parse_attribute("pawnTypes", v->promotionPawnType[WHITE], v->pieceToChar);
     parse_attribute("pawnTypes", v->promotionPawnType[BLACK], v->pieceToChar);
@@ -433,7 +439,6 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute("capturesToHand", v->capturesToHand);
     parse_attribute("firstRankPawnDrops", v->firstRankPawnDrops);
     parse_attribute("promotionZonePawnDrops", v->promotionZonePawnDrops);
-    parse_attribute("dropOnTop", v->dropOnTop);
     parse_attribute("enclosingDrop", v->enclosingDrop);
     parse_attribute("enclosingDropStart", v->enclosingDropStart);
     parse_attribute("whiteDropRegion", v->whiteDropRegion);
@@ -502,6 +507,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute("connectHorizontal", v->connectHorizontal);
     parse_attribute("connectVertical", v->connectVertical);
     parse_attribute("connectDiagonal", v->connectDiagonal);
+    parse_attribute("connectNxN", v->connectNxN);
     parse_attribute("materialCounting", v->materialCounting);
     parse_attribute("countingRule", v->countingRule);
     parse_attribute("castlingWins", v->castlingWins);
index 39f4888..c72a07f 100644 (file)
@@ -2806,6 +2806,19 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
           }
       }
   }
+
+  if (connect_nxn())
+  {
+      Bitboard connectors = pieces(~sideToMove);
+      for (int i = 1; i < connect_nxn() && connectors; i++)
+          connectors &= shift<SOUTH>(connectors) & shift<EAST>(connectors) & shift<SOUTH_EAST>(connectors);
+      if (connectors)
+      {
+          result = mated_in(ply);
+          return true;
+      }
+  }
+
   // Check for bikjang rule (Janggi) and double passing
   if (st->pliesFromNull > 0 && ((st->bikjang && st->previous->bikjang) || (st->pass && st->previous->pass)))
   {
index 7b9b4cd..81c61dd 100644 (file)
@@ -167,7 +167,6 @@ public:
   bool drop_loop() const;
   bool captures_to_hand() const;
   bool first_rank_pawn_drops() const;
-  bool drop_on_top() const;
   bool can_drop(Color c, PieceType pt) const;
   EnclosingRule enclosing_drop() const;
   Bitboard drop_region(Color c) const;
@@ -210,6 +209,7 @@ public:
   bool connect_vertical() const;
   bool connect_diagonal() const;
   const std::vector<Direction>& getConnectDirections() const;
+  int connect_nxn() const;
 
   CheckCount checks_remaining(Color c) const;
   MaterialCounting material_counting() const;
@@ -373,6 +373,7 @@ private:
   void remove_from_hand(Piece pc);
   void drop_piece(Piece pc_hand, Piece pc_drop, Square s);
   void undrop_piece(Piece pc_hand, Square s);
+  Bitboard find_drop_region(Direction dir, Square s, Bitboard occupied) const;
 };
 
 extern std::ostream& operator<<(std::ostream& os, const Position& pos);
@@ -648,11 +649,6 @@ inline bool Position::first_rank_pawn_drops() const {
   return var->firstRankPawnDrops;
 }
 
-inline bool Position::drop_on_top() const {
-  assert(var != nullptr);
-  return var->dropOnTop;
-}
-
 inline EnclosingRule Position::enclosing_drop() const {
   assert(var != nullptr);
   return var->enclosingDrop;
@@ -666,9 +662,6 @@ inline Bitboard Position::drop_region(Color c) const {
 inline Bitboard Position::drop_region(Color c, PieceType pt) const {
   Bitboard b = drop_region(c) & board_bb(c, pt);
 
-  // Connect4-style drops
-  if (drop_on_top())
-      b &= shift<NORTH>(pieces()) | Rank1BB;
   // Pawns on back ranks
   if (pt == PAWN)
   {
@@ -686,7 +679,6 @@ inline Bitboard Position::drop_region(Color c, PieceType pt) const {
   if (pt == ROOK && sittuyin_rook_drop())
       b &= rank_bb(relative_rank(c, RANK_1, max_rank()));
 
-  // Filter out squares where the drop does not enclose at least one opponent's piece
   if (enclosing_drop())
   {
       // Reversi start
@@ -694,6 +686,7 @@ inline Bitboard Position::drop_region(Color c, PieceType pt) const {
           b &= var->enclosingDropStart;
       else
       {
+          // Filter out squares where the drop does not enclose at least one opponent's piece
           if (enclosing_drop() == REVERSI)
           {
               Bitboard theirs = pieces(~c);
@@ -715,6 +708,40 @@ inline Bitboard Position::drop_region(Color c, PieceType pt) const {
               b &=   ~(shift<NORTH     >(theirs) | shift<SOUTH     >(theirs)
                   | shift<EAST      >(theirs) | shift<WEST      >(theirs));
           }
+          else if (enclosing_drop() == ANYSIDE)
+          {
+              Bitboard occupied = pieces();
+              b = 0ULL;
+              Bitboard candidates = (shift<WEST>(occupied) | file_bb(max_file())) & ~occupied;
+
+              for (Rank r = RANK_1; r <= max_rank(); ++r) {
+                  if (!(occupied & make_square(FILE_A, r))) {
+                      b |= lsb(candidates & rank_bb(r));
+                  }
+              }
+              candidates = (shift<SOUTH>(occupied) | rank_bb(max_rank())) & ~occupied;
+              for (File f = FILE_A; f <= max_file(); ++f) {
+                  if (!(occupied & make_square(f, RANK_1))) {
+                      b |= lsb(candidates & file_bb(f));
+                  }
+              }
+              candidates = (shift<NORTH>(occupied) | rank_bb(RANK_1)) & ~occupied;
+              for (File f = FILE_A; f <= max_file(); ++f) {
+                  if (!(occupied & make_square(f, max_rank()))) {
+                      b |= lsb(candidates & file_bb(f));
+                  }
+              }
+              candidates = (shift<EAST>(occupied) | file_bb(FILE_A)) & ~occupied;
+              for (Rank r = RANK_1; r <= max_rank(); ++r) {
+                  if (!(occupied & make_square(max_file(), r))) {
+                      b |= lsb(candidates & rank_bb(r));
+                  }
+              }
+          }
+          else if (enclosing_drop() == TOP)
+          {
+              b &= shift<NORTH>(pieces()) | Rank1BB;
+          }
           else
           {
               assert(enclosing_drop() == ATAXX);
@@ -1026,6 +1053,11 @@ inline const std::vector<Direction>& Position::getConnectDirections() const {
     return var->connect_directions;
 }
 
+inline int Position::connect_nxn() const {
+  assert(var != nullptr);
+  return var->connectNxN;
+}
+
 inline CheckCount Position::checks_remaining(Color c) const {
   return st->checksRemaining[c];
 }
index 2fa03e7..5abfac8 100644 (file)
@@ -302,7 +302,7 @@ enum ChasingRule {
 };
 
 enum EnclosingRule {
-  NO_ENCLOSING, REVERSI, ATAXX, QUADWRANGLE, SNORT
+  NO_ENCLOSING, REVERSI, ATAXX, QUADWRANGLE, SNORT, ANYSIDE, TOP
 };
 
 enum WallingRule {
index e8899f3..79cdc5a 100644 (file)
@@ -95,7 +95,6 @@ struct Variant {
   bool capturesToHand = false;
   bool firstRankPawnDrops = false;
   bool promotionZonePawnDrops = false;
-  bool dropOnTop = false;
   EnclosingRule enclosingDrop = NO_ENCLOSING;
   Bitboard enclosingDropStart = 0;
   Bitboard whiteDropRegion = AllSquares;
@@ -153,6 +152,7 @@ struct Variant {
   bool connectHorizontal = true;
   bool connectVertical = true;
   bool connectDiagonal = true;
+  int connectNxN = 0;
   MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
   CountingRule countingRule = NO_COUNTING;
   CastlingRights castlingWins = NO_CASTLING;
index 104b038..38c6cc7 100644 (file)
 # [MaterialCounting]: material counting rules for adjudication [janggi, unweighted, whitedrawodds, blackdrawodds, none]
 # [CountingRule]: makruk, cambodian, or ASEAN counting rules [makruk, cambodian, asean, none]
 # [ChasingRule]: xiangqi chasing rules [axf, none]
-# [EnclosingRule]: reversi or ataxx enclosing rules [reversi, ataxx, quadwrangle, snort, none]
+# [EnclosingRule]: reversi, ataxx, etc. enclosing rules [reversi, ataxx, quadwrangle, snort, anyside, top, none]
+# - in enclosingDrop:
+#  - reversi: must enclose opponent's pieces between yours by Queen move
+#  - ataxx: must be adjacent to own piece by King move
+#  - snort: most *not* be adjacent to opponent's piece by Wazir move
+#  - anyside: must be reached by inserting from an edge and sliding to opposite edge
+#  - top: must be reached by inserting from top and sliding to bottom (ie. Connect 4)
+# - in flipEnclosedPieces:
+#  - reversi: flip opponent's pieces enclosed between yours by Queen move
+#  - quadwrangle: if a normal move *or* a drop with a friendly piece adjacent by King move, then flip opponent's pieces adjacent by King move
+#  - ataxx: flip opponent's pieces adjacent by King move
 # [WallingRule]: wall-placing rule [arrow, duck, edge, past, static, none]
 # - arrow: copies piece movement (ie. Game of the Amazons)
 # - duck: mobile square (ie. Duck chess)
 # capturesToHand: captured pieces go to opponent's hand [bool] (default: false)
 # firstRankPawnDrops: allow pawn drops to first rank [bool] (default: false)
 # promotionZonePawnDrops: allow pawn drops in promotion zone  [bool] (default: false)
-# dropOnTop: piece drops need to be on top of pieces on board (e.g., for connect4) [bool] (default: false)
+# dropOnTop: DEPRECATED, use "enclosingDrop = top"
 # enclosingDrop: require piece drop to enclose pieces [EnclosingRule] (default: none)
 # enclosingDropStart: drop region for starting phase disregarding enclosingDrop (e.g., for reversi) [Bitboard]
 # whiteDropRegion: restrict region for piece drops of all white pieces [Bitboard]
 # connectVertical: connectN looks at Vertical rows [bool] (default: true)
 # connectHorizontal: connectN looks at Horizontal rows [bool] (default: true)
 # connectDiagonal: connectN looks at Diagonal rows [bool] (default: true)
+# connectNxN: connect a tight NxN square for win [int] (default: 0)
 # 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: -)
@@ -490,7 +501,7 @@ maxFile = 7
 immobile = p
 startFen = 7/7/7/7/7/7[PPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppp] w - - 0 1
 pieceDrops = true
-dropOnTop = true
+enclosingDrop = top
 doubleStep = false
 castling = false
 stalemateValue = draw
@@ -1801,6 +1812,15 @@ castling = false
 doubleStep = false
 promotionRegionWhite = *6
 
+#https://www.zillions-of-games.com/cgi-bin/zilligames/submissions.cgi?do=show;id=655
+[teeko:picaria]
+maxRank = 5
+maxFile = 5
+connectN = 4
+connectNxN = 2
+customPiece1 = p:mK
+startFen = 5/5/5/5/5[PPPPpppp] w - - 0 1
+
 #https://www.chessvariants.com/small.dir/haynie.html
 [haynie:chess]
 maxRank = 6
@@ -1811,3 +1831,19 @@ promotionPieceTypes = rbq
 castlingQueensideFile = c
 castlingKingsideFile = e
 promotionRegionWhite = *6
+
+#https://www.zillions-of-games.com/cgi-bin/zilligames/submissions.cgi?do=show;id=1723
+[symphony:tictactoe]
+maxRank = 8
+maxFile = 8
+connectN = 5
+customPiece1 = p:mfsW
+nFoldRule = 3
+startFen = 8/8/8/8/8/8/8/8[PPPPPPpppppp] w - - 0
+
+#https://www.zillions-of-games.com/cgi-bin/zilligames/submissions.cgi?do=show;id=734
+#am calling it cfour-anyside so it's less confusable with roll-ing-to-four
+[cfour-anyside:cfour]
+maxRank = 7
+startFen = 7/7/7/7/7/7/7[PPPPPPPPPPPPPPPPPPPPPPPPPpppppppppppppppppppppppp] w - - 0 1
+enclosingDrop = anyside