Support Ataxx
authorFabian Fichter <ianfab@users.noreply.github.com>
Thu, 6 Aug 2020 20:25:52 +0000 (22:25 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Thu, 6 Aug 2020 21:02:45 +0000 (23:02 +0200)
https://en.wikipedia.org/wiki/Ataxx

bench: 5499014

src/evaluate.cpp
src/parser.cpp
src/piece.cpp
src/position.cpp
src/position.h
src/psqt.cpp
src/types.h
src/variant.cpp
src/variant.h
src/variants.ini
tests/perft.sh

index 9be2f55..f155c04 100644 (file)
@@ -1010,15 +1010,18 @@ namespace {
     if (pos.flip_enclosed_pieces())
     {
         // Stable pieces
-        Bitboard edges = (FileABB | file_bb(pos.max_file()) | Rank1BB | rank_bb(pos.max_rank())) & pos.board_bb();
-        Bitboard edgePieces = pos.pieces(Us) & edges;
-        while (edgePieces)
+        if (pos.flip_enclosed_pieces() == REVERSI)
         {
-            Bitboard connectedEdge = attacks_bb(Us, ROOK, pop_lsb(&edgePieces), ~(pos.pieces(Us) & edges)) & edges;
-            if (!more_than_one(connectedEdge & ~pos.pieces(Us)))
-                score += make_score(300, 300);
-            else if (!(connectedEdge & ~pos.pieces()))
-                score += make_score(200, 200);
+            Bitboard edges = (FileABB | file_bb(pos.max_file()) | Rank1BB | rank_bb(pos.max_rank())) & pos.board_bb();
+            Bitboard edgePieces = pos.pieces(Us) & edges;
+            while (edgePieces)
+            {
+                Bitboard connectedEdge = attacks_bb(Us, ROOK, pop_lsb(&edgePieces), ~(pos.pieces(Us) & edges)) & edges;
+                if (!more_than_one(connectedEdge & ~pos.pieces(Us)))
+                    score += make_score(300, 300);
+                else if (!(connectedEdge & ~pos.pieces()))
+                    score += make_score(200, 200);
+            }
         }
 
         // Unstable
@@ -1027,9 +1030,14 @@ namespace {
         while (drops)
         {
             Square s = pop_lsb(&drops);
-            Bitboard b = attacks_bb(Them, QUEEN, s, ~pos.pieces(Us)) & ~PseudoAttacks[Them][KING][s] & pos.pieces(Them);
-            while(b)
-                unstable |= between_bb(s, pop_lsb(&b));
+            if (pos.flip_enclosed_pieces() == REVERSI)
+            {
+                Bitboard b = attacks_bb(Them, QUEEN, s, ~pos.pieces(Us)) & ~PseudoAttacks[Them][KING][s] & pos.pieces(Them);
+                while(b)
+                    unstable |= between_bb(s, pop_lsb(&b));
+            }
+            else
+                unstable |= PseudoAttacks[Them][KING][s] & pos.pieces(Us);
         }
         score -= make_score(200, 200) * popcount(unstable);
     }
index dca83f8..405487f 100644 (file)
@@ -92,6 +92,13 @@ namespace {
         return value == "makruk" || value == "asean" || value == "none";
     }
 
+    template <> bool set(const std::string& value, EnclosingRule& target) {
+        target =  value == "reversi"  ? REVERSI
+                : value == "ataxx" ? ATAXX
+                : NO_ENCLOSING;
+        return value == "reversi" || value == "ataxx" || value == "none";
+    }
+
     template <> bool set(const std::string& value, Bitboard& target) {
         char file;
         int rank;
index f37333e..63344d5 100644 (file)
@@ -290,6 +290,15 @@ namespace {
       p->name = "immobile";
       return p;
   }
+  PieceInfo* ataxx_piece() {
+      PieceInfo* p = new PieceInfo();
+      p->name = "ataxx";
+      p->betza = "mDNA";
+      p->stepsQuiet = {2 * NORTH_WEST, 2 * NORTH + WEST, 2 * NORTH, 2 * NORTH + EAST, 2 * NORTH_EAST,
+                       NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * WEST, 2 * EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+                       2 * SOUTH_WEST, 2 * SOUTH + WEST, 2 * SOUTH, 2 * SOUTH + EAST, 2 * SOUTH_EAST};
+      return p;
+  }
   PieceInfo* cannon_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "cannon";
@@ -393,6 +402,7 @@ void PieceMap::init() {
   add(CLOBBER_PIECE, clobber_piece());
   add(BREAKTHROUGH_PIECE, breakthrough_piece());
   add(IMMOBILE_PIECE, immobile_piece());
+  add(ATAXX_PIECE, ataxx_piece());
   add(CANNON, cannon_piece());
   add(JANGGI_CANNON, janggi_cannon_piece());
   add(SOLDIER, soldier_piece());
index db17d95..706c587 100644 (file)
@@ -1314,6 +1314,45 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
       st->castlingRights &= ~cr;
   }
 
+  // Flip enclosed pieces
+  st->flippedPieces = 0;
+  if (flip_enclosed_pieces() && !is_pass(m))
+  {
+      // Find end of rows to be flipped
+      if (flip_enclosed_pieces() == REVERSI)
+      {
+          Bitboard b = attacks_bb(us, QUEEN, to, board_bb() & ~pieces(~us)) & ~PseudoAttacks[us][KING][to] & pieces(us);
+          while(b)
+              st->flippedPieces |= between_bb(to, pop_lsb(&b));
+      }
+      else
+      {
+          assert(flip_enclosed_pieces() == ATAXX);
+          st->flippedPieces = PseudoAttacks[us][KING][to] & pieces(~us);
+      }
+
+      // Flip pieces
+      Bitboard to_flip = st->flippedPieces;
+      while(to_flip)
+      {
+          Square s = pop_lsb(&to_flip);
+          Piece flipped = piece_on(s);
+          Piece resulting = ~flipped;
+
+          // remove opponent's piece
+          remove_piece(s);
+          k ^= Zobrist::psq[flipped][s];
+          st->materialKey ^= Zobrist::psq[flipped][pieceCount[flipped]];
+          st->nonPawnMaterial[them] -= PieceValue[MG][flipped];
+
+          // add our piece
+          put_piece(resulting, s);
+          k ^= Zobrist::psq[resulting][s];
+          st->materialKey ^= Zobrist::psq[resulting][pieceCount[resulting]-1];
+          st->nonPawnMaterial[us] += PieceValue[MG][resulting];
+      }
+  }
+
   // Move the piece. The tricky Chess960 castling is handled earlier
   if (type_of(m) == DROP)
   {
@@ -1339,35 +1378,6 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
                   set_castling_right(us, to);
           }
       }
-      // Flip enclosed pieces
-      if (flip_enclosed_pieces())
-      {
-          st->flippedPieces = 0;
-          // Find end of rows to be flipped
-          Bitboard b = attacks_bb(us, QUEEN, to, board_bb() & ~pieces(~us)) & ~PseudoAttacks[us][KING][to] & pieces(us);
-          while(b)
-              st->flippedPieces |= between_bb(to, pop_lsb(&b));
-          // Flip pieces
-          Bitboard to_flip = st->flippedPieces;
-          while(to_flip)
-          {
-              Square s = pop_lsb(&to_flip);
-              Piece flipped = piece_on(s);
-              Piece resulting = ~flipped;
-
-              // remove opponent's piece
-              remove_piece(s);
-              k ^= Zobrist::psq[flipped][s];
-              st->materialKey ^= Zobrist::psq[flipped][pieceCount[flipped]];
-              st->nonPawnMaterial[them] -= PieceValue[MG][flipped];
-
-              // add our piece
-              put_piece(resulting, s);
-              k ^= Zobrist::psq[resulting][s];
-              st->materialKey ^= Zobrist::psq[resulting][pieceCount[resulting]-1];
-              st->nonPawnMaterial[us] += PieceValue[MG][resulting];
-          }
-      }
   }
   else if (type_of(m) != CASTLING)
       move_piece(from, to);
@@ -1572,21 +1582,7 @@ void Position::undo_move(Move m) {
   else
   {
       if (type_of(m) == DROP)
-      {
-          if (flip_enclosed_pieces())
-          {
-              // Flip pieces
-              Bitboard to_flip = st->flippedPieces;
-              while(to_flip)
-              {
-                  Square s = pop_lsb(&to_flip);
-                  Piece resulting = ~piece_on(s);
-                  remove_piece(s);
-                  put_piece(resulting, s);
-              }
-          }
           undrop_piece(make_piece(us, in_hand_piece_type(m)), to); // Remove the dropped piece
-      }
       else
           move_piece(to, from); // Put the piece back at the source square
 
@@ -1613,6 +1609,19 @@ void Position::undo_move(Move m) {
       }
   }
 
+  if (flip_enclosed_pieces())
+  {
+      // Flip pieces
+      Bitboard to_flip = st->flippedPieces;
+      while(to_flip)
+      {
+          Square s = pop_lsb(&to_flip);
+          Piece resulting = ~piece_on(s);
+          remove_piece(s);
+          put_piece(resulting, s);
+      }
+  }
+
   // Finally point our state pointer back to the previous state
   st = st->previous;
   --gamePly;
index 4446b08..ad6b854 100644 (file)
@@ -133,7 +133,7 @@ public:
   bool captures_to_hand() const;
   bool first_rank_pawn_drops() const;
   bool drop_on_top() const;
-  bool enclosing_drop() const;
+  EnclosingRule enclosing_drop() const;
   Bitboard drop_region(Color c) const;
   Bitboard drop_region(Color c, PieceType pt) const;
   bool sittuyin_rook_drop() const;
@@ -149,7 +149,7 @@ public:
   bool pass_on_stalemate() const;
   Bitboard promoted_soldiers(Color c) const;
   bool makpong() const;
-  bool flip_enclosed_pieces() const;
+  EnclosingRule flip_enclosed_pieces() const;
   // winning conditions
   int n_move_rule() const;
   int n_fold_rule() const;
@@ -511,7 +511,7 @@ inline bool Position::drop_on_top() const {
   return var->dropOnTop;
 }
 
-inline bool Position::enclosing_drop() const {
+inline EnclosingRule Position::enclosing_drop() const {
   assert(var != nullptr);
   return var->enclosingDrop;
 }
@@ -552,17 +552,29 @@ inline Bitboard Position::drop_region(Color c, PieceType pt) const {
           b &= var->enclosingDropStart;
       else
       {
-          Bitboard theirs = pieces(~c);
-          b &=  shift<NORTH     >(theirs) | shift<SOUTH     >(theirs)
-              | shift<NORTH_EAST>(theirs) | shift<SOUTH_WEST>(theirs)
-              | shift<EAST      >(theirs) | shift<WEST      >(theirs)
-              | shift<SOUTH_EAST>(theirs) | shift<NORTH_WEST>(theirs);
-          Bitboard b2 = b;
-          while (b2)
+          if (enclosing_drop() == REVERSI)
           {
-              Square s = pop_lsb(&b2);
-              if (!(attacks_bb(c, QUEEN, s, board_bb() & ~pieces(~c)) & ~PseudoAttacks[c][KING][s] & pieces(c)))
-                  b ^= s;
+              Bitboard theirs = pieces(~c);
+              b &=  shift<NORTH     >(theirs) | shift<SOUTH     >(theirs)
+                  | shift<NORTH_EAST>(theirs) | shift<SOUTH_WEST>(theirs)
+                  | shift<EAST      >(theirs) | shift<WEST      >(theirs)
+                  | shift<SOUTH_EAST>(theirs) | shift<NORTH_WEST>(theirs);
+              Bitboard b2 = b;
+              while (b2)
+              {
+                  Square s = pop_lsb(&b2);
+                  if (!(attacks_bb(c, QUEEN, s, board_bb() & ~pieces(~c)) & ~PseudoAttacks[c][KING][s] & pieces(c)))
+                      b ^= s;
+              }
+          }
+          else
+          {
+              assert(enclosing_drop() == ATAXX);
+              Bitboard ours = pieces(c);
+              b &=  shift<NORTH     >(ours) | shift<SOUTH     >(ours)
+                  | shift<NORTH_EAST>(ours) | shift<SOUTH_WEST>(ours)
+                  | shift<EAST      >(ours) | shift<WEST      >(ours)
+                  | shift<SOUTH_EAST>(ours) | shift<NORTH_WEST>(ours);
           }
       }
   }
@@ -645,7 +657,7 @@ inline int Position::n_fold_rule() const {
   return var->nFoldRule;
 }
 
-inline bool Position::flip_enclosed_pieces() const {
+inline EnclosingRule Position::flip_enclosed_pieces() const {
   assert(var != nullptr);
   return var->flipEnclosedPieces;
 }
index 2c8aabf..f853dbf 100644 (file)
@@ -190,7 +190,7 @@ void init(const Variant* v) {
                                                 : make_score(10, 10) * (1 + isSlowLeaper) * (f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - v->maxFile / 2));
           if (pt == SOLDIER && r < v->soldierPromotionRank)
               psq[pc][s] -= score * (v->soldierPromotionRank - r) / (4 + f);
-          if (v->enclosingDrop)
+          if (v->enclosingDrop == REVERSI)
           {
               if (f == FILE_A && (r == RANK_1 || r == v->maxRank))
                   psq[pc][s] += make_score(1000, 1000);
index edc7c68..006ac75 100644 (file)
@@ -282,6 +282,10 @@ enum CountingRule {
   NO_COUNTING, MAKRUK_COUNTING, ASEAN_COUNTING
 };
 
+enum EnclosingRule {
+  NO_ENCLOSING, REVERSI, ATAXX
+};
+
 enum Phase {
   PHASE_ENDGAME,
   PHASE_MIDGAME = 128,
@@ -343,6 +347,7 @@ enum Value : int {
   ClobberPieceValueMg      = 300,   ClobberPieceValueEg      = 300,
   BreakthroughPieceValueMg = 300,   BreakthroughPieceValueEg = 300,
   ImmobilePieceValueMg     = 50,    ImmobilePieceValueEg     = 50,
+  AtaxxPieceValueMg        = 100,   AtaxxPieceValueEg        = 100,
   CannonPieceValueMg       = 800,   CannonPieceValueEg       = 700,
   JanggiCannonPieceValueMg = 800,   JanggiCannonPieceValueEg = 600,
   SoldierValueMg           = 200,   SoldierValueEg           = 270,
@@ -365,7 +370,7 @@ enum PieceType {
   FERS, MET = FERS, ALFIL, FERS_ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS,
   ARCHBISHOP, CHANCELLOR, AMAZON, KNIBIS, BISKNI, KNIROO, ROOKNI,
   SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, DRAGON_HORSE,
-  CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, CANNON, JANGGI_CANNON,
+  CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, ATAXX_PIECE, CANNON, JANGGI_CANNON,
   SOLDIER, HORSE, ELEPHANT, JANGGI_ELEPHANT, BANNER,
   WAZIR, COMMONER, CENTAUR, KING,
   ALL_PIECES = 0,
@@ -402,9 +407,9 @@ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = {
     FersValueMg, AlfilValueMg, FersAlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
     ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg, KnirooValueMg, RookniValueMg,
     ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, DragonHorseValueMg,
-    ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg,
+    ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg, AtaxxPieceValueMg,
     CannonPieceValueMg, JanggiCannonPieceValueMg, SoldierValueMg, HorseValueMg, ElephantValueMg, JanggiElephantValueMg, BannerValueMg,
-    WazirValueMg, CommonerValueMg, CentaurValueMg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
+    WazirValueMg, CommonerValueMg, CentaurValueMg, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
@@ -414,9 +419,9 @@ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = {
     FersValueMg, AlfilValueMg, FersAlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
     ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg, KnirooValueMg, RookniValueMg,
     ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, DragonHorseValueMg,
-    ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg,
+    ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg, AtaxxPieceValueMg,
     CannonPieceValueMg, JanggiCannonPieceValueMg, SoldierValueMg, HorseValueMg, ElephantValueMg, JanggiElephantValueMg, BannerValueMg,
-    WazirValueMg, CommonerValueMg, CentaurValueMg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
+    WazirValueMg, CommonerValueMg, CentaurValueMg, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
@@ -426,9 +431,9 @@ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = {
     FersValueEg, AlfilValueEg, FersAlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
     ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg, KnirooValueEg, RookniValueEg,
     ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, DragonHorseValueEg,
-    ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg,
+    ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg, AtaxxPieceValueEg,
     CannonPieceValueEg, JanggiCannonPieceValueEg, SoldierValueEg, HorseValueEg, ElephantValueEg, JanggiElephantValueEg, BannerValueEg,
-    WazirValueEg, CommonerValueEg, CentaurValueEg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
+    WazirValueEg, CommonerValueEg, CentaurValueEg, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
@@ -438,9 +443,9 @@ constexpr Value PieceValue[PHASE_NB][PIECE_NB] = {
     FersValueEg, AlfilValueEg, FersAlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
     ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg, KnirooValueEg, RookniValueEg,
     ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, DragonHorseValueEg,
-    ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg,
+    ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg, AtaxxPieceValueEg,
     CannonPieceValueEg, JanggiCannonPieceValueEg, SoldierValueEg, HorseValueEg, ElephantValueEg, JanggiElephantValueEg, BannerValueEg,
-    WazirValueEg, CommonerValueEg, CentaurValueEg, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
+    WazirValueEg, CommonerValueEg, CentaurValueEg, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
     VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO, VALUE_ZERO,
index 77365f5..999198d 100644 (file)
@@ -606,6 +606,27 @@ namespace {
         v->blackFlag = Rank1BB;
         return v;
     }
+    Variant* ataxx_variant() {
+        Variant* v = fairy_variant_base();
+        v->pieceToCharTable = "P.................p.................";
+        v->maxRank = RANK_7;
+        v->maxFile = FILE_G;
+        v->reset_pieces();
+        v->add_piece(ATAXX_PIECE, 'p');
+        v->startFen = "P5p/7/7/7/7/7/p5P[PPPPPPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppppppp] w 0 1";
+        v->promotionPieceTypes = {};
+        v->pieceDrops = true;
+        v->doubleStep = false;
+        v->castling = false;
+        v->immobilityIllegal = false;
+        v->stalemateValue = -VALUE_MATE;
+        v->stalematePieceCount = true;
+        v->passOnStalemate = true;
+        v->enclosingDrop = ATAXX;
+        v->flipEnclosedPieces = ATAXX;
+        v->materialCounting = UNWEIGHTED_MATERIAL;
+        return v;
+    }
     Variant* minixiangqi_variant() {
         Variant* v = fairy_variant_base();
         v->variantTemplate = "xiangqi";
@@ -967,6 +988,7 @@ void VariantMap::init() {
     add("shatar", shatar_variant());
     add("clobber", clobber_variant());
     add("breakthrough", breakthrough_variant());
+    add("ataxx", ataxx_variant());
     add("minixiangqi", minixiangqi_variant());
 #ifdef LARGEBOARDS
     add("shogi", shogi_variant());
index 27065dc..ad51aa5 100644 (file)
@@ -76,7 +76,7 @@ struct Variant {
   bool firstRankPawnDrops = false;
   bool promotionZonePawnDrops = false;
   bool dropOnTop = false;
-  bool enclosingDrop = false;
+  EnclosingRule enclosingDrop = NO_ENCLOSING;
   Bitboard enclosingDropStart = 0;
   Bitboard whiteDropRegion = AllSquares;
   Bitboard blackDropRegion = AllSquares;
@@ -94,7 +94,7 @@ struct Variant {
   bool makpongRule = false;
   bool flyingGeneral = false;
   Rank soldierPromotionRank = RANK_1;
-  bool flipEnclosedPieces = false;
+  EnclosingRule flipEnclosedPieces = NO_ENCLOSING;
   // game end
   int nMoveRule = 50;
   int nFoldRule = 3;
index 1dcfc0d..d0f62e9 100644 (file)
@@ -73,6 +73,7 @@
 # clobber
 # breakthrough
 # immobile (piece without moves)
+# ataxx (mDNA)
 # cannon
 # janggiCannon
 # soldier
@@ -95,6 +96,7 @@
 # [Value]: game result for the side to move [win, loss, draw]
 # [MaterialCounting]: material couting rules for adjudication [janggi, unweighted, whitedrawodds, blackdrawodds, none]
 # [CountingRule]: makruk or ASEAN counting rules [makruk, asean, none]
+# [EnclosingRule]: reversi or ataxx enclosing rules [reversi, ataxx, none]
 
 ### Rule definition options
 # variantTemplate: only relevant for usage in XBoard/WinBoard GUI [values: fairy, shogi] (default: fairy)
 # 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)
-# enclosingDrop: require piece drop to enclose opponent's pieces (e.g., for othello) [bool] (default: false)
+# 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]
 # blackDropRegion: restrict region for piece drops of all black pieces [Bitboard]
 # 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 [bool] (default: 1)
-# flipEnclosedPieces: change color of pieces that are enclosed by a drop (e.g., for othello) [bool] (default: false)
+# flipEnclosedPieces: change color of pieces that are enclosed by a drop [EnclosingRule] (default: none)
 # nMoveRule: move count for 50/n-move rule [int] (default: 50)
 # nFoldRule: move count for 3/n-fold repetition rule [int] (default: 3)
 # nFoldValue: result in case of 3/n-fold repetition [Value] (default: draw)
@@ -314,10 +316,10 @@ castling = false
 stalemateValue = loss
 stalematePieceCount = true
 materialCounting = unweighted
-enclosingDrop = true
+enclosingDrop = reversi
 enclosingDropStart = d4 e4 d5 e5
 immobilityIllegal = false
-flipEnclosedPieces = true
+flipEnclosedPieces = reversi
 passOnStalemate = false
 
 [othello:reversi]
index 354fc9b..5606723 100755 (executable)
@@ -62,6 +62,8 @@ if [[ $1 == "" || $1 == "variant" ]]; then
   expect perft.exp sittuyin "fen 8/6s1/5P2/3n4/pR2K2S/1P6/1k4p1/8[] w - - 1 50" 4 268869 > /dev/null
   expect perft.exp seirawan startpos 5 27639803 > /dev/null
   expect perft.exp seirawan "fen reb1k2r/ppppqppp/2nb1n2/4p3/4P3/N1P2N2/PB1PQPPP/RE2KBHR[h] b KQkqc - 3 7" 5 31463761 > /dev/null
+  expect perft.exp ataxx startpos 4 155888 > /dev/null
+  expect perft.exp ataxx "fen 7/7/7/7/ppppppp/ppppppp/PPPPPPP[PPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppp] w 0 1" 5 452980 > /dev/null
 fi
 
 # large-board variants