add Gale (#724)
authorRainRat <rainrat78@yahoo.ca>
Tue, 31 Oct 2023 10:26:38 +0000 (03:26 -0700)
committerGitHub <noreply@github.com>
Tue, 31 Oct 2023 10:26:38 +0000 (11:26 +0100)
and improve bitboard parsing

src/parser.cpp
src/position.cpp
src/variant.h
src/variants.ini

index 1c4b4fa..c925b2d 100644 (file)
@@ -124,19 +124,36 @@ namespace {
     }
 
     template <> bool set(const std::string& value, Bitboard& target) {
-        char file;
-        int rank;
+        std::string symbol;
         std::stringstream ss(value);
         target = 0;
-        while (!ss.eof() && ss >> file && file != '-' && ss >> rank)
+        while (!ss.eof() && ss >> symbol && symbol != "-")
         {
-            if (Rank(rank - 1) > RANK_MAX || (file != '*' && File(tolower(file) - 'a') > FILE_MAX))
+            if (symbol.back() == '*') {
+                if (isalpha(symbol[0]) && symbol.length() == 2) {
+                    char file = tolower(symbol[0]);
+                    if (File(file - 'a') > FILE_MAX) return false;
+                    target |= file_bb(File(file - 'a'));
+                } else {
+                    return false;
+                }
+            } else if (symbol[0] == '*') {
+                int rank = std::stoi(symbol.substr(1));
+                if (Rank(rank - 1) > RANK_MAX) return false;
+                target |= rank_bb(Rank(rank - 1));
+            } else if (isalpha(symbol[0]) && symbol.length() > 1) {
+                char file = tolower(symbol[0]);
+                int rank = std::stoi(symbol.substr(1));
+                if (Rank(rank - 1) > RANK_MAX || File(file - 'a') > FILE_MAX) return false;
+                target |= square_bb(make_square(File(file - 'a'), Rank(rank - 1)));
+            } else {
                 return false;
-            target |= file == '*' ? rank_bb(Rank(rank - 1)) : square_bb(make_square(File(tolower(file) - 'a'), Rank(rank - 1)));
+            }
         }
         return !ss.fail();
     }
 
+
     template <> bool set(const std::string& value, CastlingRights& target) {
         char c;
         CastlingRights castlingRight;
@@ -507,6 +524,10 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute("connectHorizontal", v->connectHorizontal);
     parse_attribute("connectVertical", v->connectVertical);
     parse_attribute("connectDiagonal", v->connectDiagonal);
+    parse_attribute("connectRegion1White", v->connectRegion1[WHITE]);
+    parse_attribute("connectRegion2White", v->connectRegion2[WHITE]);
+    parse_attribute("connectRegion1Black", v->connectRegion1[BLACK]);
+    parse_attribute("connectRegion2Black", v->connectRegion2[BLACK]);
     parse_attribute("connectNxN", v->connectNxN);
     parse_attribute("materialCounting", v->materialCounting);
     parse_attribute("countingRule", v->countingRule);
index c72a07f..9b8ce39 100644 (file)
@@ -2807,6 +2807,32 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
       }
   }
 
+  if ((var->connectRegion1[~sideToMove] & pieces(~sideToMove)) && (var->connectRegion2[~sideToMove] & pieces(~sideToMove)))
+  {
+      Bitboard target = var->connectRegion2[~sideToMove];
+      Bitboard current = var->connectRegion1[~sideToMove] & pieces(~sideToMove);
+
+      while (true) {
+          Bitboard newBitboard = 0;
+          for (Direction d : var->connect_directions) {
+              newBitboard |= shift(d, current | newBitboard) & pieces(~sideToMove); // the "| newBitboard" here probably saves a few loops
+          }
+
+          if (newBitboard & target) {
+              // A connection has been made
+              result = mated_in(ply);
+              return true;
+          }
+
+          if (!(newBitboard & ~current)) {
+              // The expansion got stuck; no further squares to explore
+              break;
+          }
+
+          current |= newBitboard;
+      }
+  }
+  
   if (connect_nxn())
   {
       Bitboard connectors = pieces(~sideToMove);
index 79cdc5a..49bc544 100644 (file)
@@ -152,6 +152,8 @@ struct Variant {
   bool connectHorizontal = true;
   bool connectVertical = true;
   bool connectDiagonal = true;
+  Bitboard connectRegion1[COLOR_NB] = {};
+  Bitboard connectRegion2[COLOR_NB] = {};
   int connectNxN = 0;
   MaterialCounting materialCounting = NO_MATERIAL_COUNTING;
   CountingRule countingRule = NO_COUNTING;
index 926fa42..b7dd011 100644 (file)
 # 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)
+# connectRegion1White: connect Region 1 to Region 2 for win. obeys connectVertical, connectHorizontal, connectDiagonal [Bitboard] (default: -)
+# connectRegion2White: "
+# connectRegion1Black: "
+# connectRegion2Black: "
 # 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)
@@ -1783,6 +1787,19 @@ extinctionPieceTypes = kq
 extinctionPseudoRoyal = true
 stalemateValue = loss
 
+#https://www.ludii.games/details.php?keyword=Gale
+[gale:snort]
+maxRank = 9
+maxFile = 9
+startFen = 1p1p1p1p1/P1P1P1P1P/1p1p1p1p1/P1P1P1P1P/1p1p1p1p1/P1P1P1P1P/1p1p1p1p1/P1P1P1P1P/1p1p1p1p1
+enclosingDrop = none
+connectRegion1White = a*
+connectRegion2White = i*
+connectRegion1Black = *1
+connectRegion2Black = *9
+#should be impossible anyway
+connectDiagonal = false
+
 #https://www.chessvariants.com/boardrules.dir/atlantis.html
 [atlantis:chess]
 wallingRule = edge