Flagvariants (#638)
authorRainRat <rainrat78@yahoo.ca>
Sat, 22 Apr 2023 12:15:24 +0000 (05:15 -0700)
committerGitHub <noreply@github.com>
Sat, 22 Apr 2023 12:15:24 +0000 (14:15 +0200)
README.md
src/parser.cpp
src/position.cpp
src/position.h
src/variant.cpp
src/variant.h
src/variants.ini

index d8194ce..f118cf3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -77,7 +77,9 @@ The games currently supported besides chess are listed below. Fairy-Stockfish ca
 - [Breakthrough](https://en.wikipedia.org/wiki/Breakthrough_(board_game))
 - [Clobber](https://en.wikipedia.org/wiki/Clobber)
 - [Cfour](https://en.wikipedia.org/wiki/Connect_Four), [Tic-tac-toe](https://en.wikipedia.org/wiki/Tic-tac-toe)
+- [Five Field Kono](https://en.wikipedia.org/wiki/Five_Field_Kono)
 - [Flipersi](https://en.wikipedia.org/wiki/Reversi), [Flipello](https://en.wikipedia.org/wiki/Reversi#Othello)
+- [Fox and Hounds](https://boardgamegeek.com/boardgame/148180/fox-and-hounds)
 - [Isolation](https://boardgamegeek.com/boardgame/1875/isolation)
 - [Joust](https://www.chessvariants.com/programs.dir/joust.html)
 - [Snailtrail](https://boardgamegeek.com/boardgame/37135/snailtrail)
index 9907a5b..d7eab8e 100644 (file)
@@ -450,6 +450,7 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
     parse_attribute("flagRegionWhite", v->flagRegion[WHITE]);
     parse_attribute("flagRegionBlack", v->flagRegion[BLACK]);
     parse_attribute("flagPieceCount", v->flagPieceCount);
+    parse_attribute("flagPieceBlockedWin", v->flagPieceBlockedWin);
     parse_attribute("flagMove", v->flagMove);
     parse_attribute("checkCounting", v->checkCounting);
     parse_attribute("connectN", v->connectN);
index f193420..0e52486 100644 (file)
@@ -2675,15 +2675,52 @@ bool Position::is_immediate_game_end(Value& result, int ply) const {
   // capture the flag
   if (   capture_the_flag_piece()
       && flag_move()
-      && (popcount(capture_the_flag(sideToMove) & pieces(sideToMove, capture_the_flag_piece()))>=flag_piece_count()))
-  {
-      result =  (popcount(capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece()))>=flag_piece_count())
-              && sideToMove == WHITE ? VALUE_DRAW : mate_in(ply);
+      && (
+           (popcount(capture_the_flag(sideToMove) & pieces(sideToMove, capture_the_flag_piece()))>=flag_piece_count()) // opponent has >= number of pieces needed to win
+           || //-or-
+           (
+             (flag_piece_blocked_win()) //flagPieceBlockedWin variant option true
+             && //-and-
+             (capture_the_flag(sideToMove) & pieces(sideToMove, capture_the_flag_piece())) //at least one piece in flag zone
+             && //-and-
+             !(capture_the_flag(sideToMove) & ~pieces()) //no empty squares in flag zone
+           )
+         )
+     )
+  {
+      result =
+           (
+             (
+               (popcount(capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece()))>=flag_piece_count()) // you have >= number of pieces needed to win
+               || //-or-
+               (
+                 (flag_piece_blocked_win()) //flagPieceBlockedWin variant option true
+                 && //-and-
+                 (capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece())) //at least one piece in flag zone
+                 && //-and-
+                 !(capture_the_flag(~sideToMove) & ~pieces()) //no empty squares in flag zone
+               )
+             )
+             &&
+               (sideToMove == WHITE) //opponent is white
+           )
+           ? VALUE_DRAW : mate_in(ply); //then it's a draw, otherwise, win
       return true;
   }
   if (   capture_the_flag_piece()
-      && (!flag_move() || capture_the_flag_piece() == KING)
-      && (popcount(capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece()))>=flag_piece_count()) )
+      && (!flag_move() || capture_the_flag_piece() == KING) //if black doesn't get an extra move to draw, or flag piece is king,
+      && ( //-and-
+           (popcount(capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece()))>=flag_piece_count()) // you have >= number of pieces needed to win
+           || //-or-
+           (
+               (flag_piece_blocked_win()) //flagPieceBlockedWin variant option true
+             && //-and-
+               (capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece())) //at least one piece in flag zone
+             && //-and-
+               !(capture_the_flag(~sideToMove) & ~pieces()) //no empty squares in flag zone
+           )
+         )
+     )
   {
       bool gameEnd = true;
       // Check whether king can move to CTF zone
index 6e179c8..6cd9f6b 100644 (file)
@@ -202,6 +202,7 @@ public:
   bool flag_move() const;
   bool check_counting() const;
   int flag_piece_count() const;
+  bool flag_piece_blocked_win() const;
   int connect_n() const;
   CheckCount checks_remaining(Color c) const;
   MaterialCounting material_counting() const;
@@ -936,6 +937,11 @@ inline int Position::flag_piece_count() const {
   return var->flagPieceCount;
 }
 
+inline bool Position::flag_piece_blocked_win() const {
+  assert(var != nullptr);
+  return var->flagPieceBlockedWin;
+}
+
 inline bool Position::check_counting() const {
   assert(var != nullptr);
   return var->checkCounting;
index fd8564f..6a020a7 100644 (file)
@@ -542,20 +542,6 @@ namespace {
         return v;
     }
 
-    Variant* kono_variant() { //https://en.wikipedia.org/wiki/Five_Field_Kono
-        Variant* v = chess_variant_base()->init();
-        v->maxRank = RANK_5;
-        v->maxFile = FILE_E;
-        v->reset_pieces();
-        v->add_piece(CUSTOM_PIECE_1, 'p', "mF"); //diagonally, no capture
-        v->startFen = "ppppp/p3p/5/P3P/PPPPP w - - 0 1";
-        v->flagPiece = CUSTOM_PIECE_1;
-        v->flagRegion[WHITE] = make_bitboard(SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_A4, SQ_E4);
-        v->flagRegion[BLACK] = make_bitboard(SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_A2, SQ_E2);
-        v->flagPieceCount = 7;
-        return v;
-    }
-
     Variant* fox_and_hounds_variant() { //https://boardgamegeek.com/boardgame/148180/fox-and-hounds
         Variant* v = chess_variant_base()->init();
         v->reset_pieces();
@@ -1582,7 +1568,7 @@ namespace {
         v->remove_piece(KNIGHT);
         v->add_piece(CHANCELLOR, 'w'); // wolf
         v->add_piece(ARCHBISHOP, 'f'); // fox
-        v->add_piece(CUSTOM_PIECE_1, 's', "fKifmnD"); // seargent
+        v->add_piece(CUSTOM_PIECE_1, 's', "fKifmnD"); // sergeant
         v->add_piece(CUSTOM_PIECE_2, 'n', "NN"); // nightrider
         v->add_piece(CUSTOM_PIECE_3, 'e', "NNQ"); // elephant
         v->startFen = "qwfrbbnk/pssppssp/1pp2pp1/8/8/8/8/1PP2PP1/PSSPPSSP/KNBBRFWQ w - - 0 1";
@@ -1816,7 +1802,6 @@ void VariantMap::init() {
     add("isolation7x7", isolation7x7_variant());
     add("snailtrail", snailtrail_variant());
     add("fox-and-hounds", fox_and_hounds_variant());
-    add("kono", kono_variant());
 #ifdef ALLVARS
     add("duck", duck_variant());
 #endif
index 085e9b4..891b039 100644 (file)
@@ -144,6 +144,7 @@ struct Variant {
   PieceType flagPiece = NO_PIECE_TYPE;
   Bitboard flagRegion[COLOR_NB] = {};
   int flagPieceCount = 1;
+  bool flagPieceBlockedWin = false;
   bool flagMove = false;
   bool checkCounting = false;
   int connectN = 0;
index 361c237..c882be3 100644 (file)
 # [PieceSet]: multiple piece types [letters defined for pieces, e.g., nbrq]
 # [Bitboard]: list of squares [e.g., d4 e4 d5 e5]. * can be used as wildcard for files (e.g., *1 is the first rank)
 # [Value]: game result for the side to move [win, loss, draw]
-# [MaterialCounting]: material couting rules for adjudication [janggi, unweighted, whitedrawodds, blackdrawodds, none]
+# [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, none]
 # flagMove: black gets one more move after white captures the flag [bool] (default: false)
 # checkCounting: enable check count win rule (check count is communicated via FEN, see 3check) [bool] (default: false)
 # flagPieceCount: number of flag pieces that have to be in the flag zone [int] (default: 1)
+# flagPieceBlockedWin: for flagPieceCount > 1. if at least one piece in flag zone and all others occupied by opponent pieces, win. [bool] (default: false)
 # connectN: number of aligned pieces for win [int] (default: 0)
 # materialCounting: enable material counting rules [MaterialCounting] (default: none)
 # countingRule: enable counting rules [CountingRule] (default: none)
@@ -1247,7 +1248,7 @@ promotionRegionWhite = *1 *2 *3 *4 *5 *6 *7 *8 *9
 promotionRegionBlack = *9 *8 *7 *6 *5 *4 *3 *2 *1
 
 # Chess vs Hoppel-Poppel
-# Assymetrical game, Chess army vs Hoppel Poppel army. Credits to Procyon for the definition.
+# Asymmetrical game, Chess army vs Hoppel Poppel army. Credits to Procyon for the definition.
 # Variant defined in Pychess discord and previously playable with Chessboi bot.
 [chessvshp:chess]
 soldier = s
@@ -1263,7 +1264,7 @@ pieceToCharTable = PNBRQ.......IJ.......Kpnbrq.......ij.......k
 startFen = rijqkjir/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
 
 # Orda vs Empire
-# Assymetrical game, Empire army vs Orda army. Empire (as Black again), no Soldiers, 8 x Imperial Pawns but on the 3rd rank. Empire rules in place. Yurt is a mNcK. Credits to Procyon for the definition.
+# Asymmetrical game, Empire army vs Orda army. Empire (as Black again), no Soldiers, 8 x Imperial Pawns but on the 3rd rank. Empire rules in place. Yurt is a mNcK. Credits to Procyon for the definition.
 # Variant defined in Pychess discord and previously playable with Chessboi bot.
 [ordavsempire:chess]
 centaur = h
@@ -1291,6 +1292,68 @@ pieceToCharTable = P...Q..AH..ECTDY....LKp...q..ah..ectdy....lk
 duckGating = true
 stalemateValue = win
 
+[kono]
+maxRank = 5
+maxFile = e
+customPiece1 = p:mF
+startFen = ppppp/p3p/5/P3P/PPPPP w - - 0 1
+flagPiece = p
+flagRegionWhite = a5 b5 c5 d5 e5 a4 e4
+flagRegionBlack = a1 b1 c1 d1 e1 a2 e2
+flagPieceCount = 7
+flagPieceBlockedWin = true
+
+#https://www.chessvariants.com/large.dir/xhess.html
+[xhess:chess]
+pieceToCharTable = HNBRQ......CI........Khnbrq......ci........k
+maxRank = 10
+maxFile = j
+promotionRegionWhite = *10
+promotionPieceTypes = nbrqci
+flagPiece = k
+flagRegionWhite = *10
+flagRegionBlack = *1
+pawnTypes = h
+cannon = c
+customPiece1 = i:NN
+customPiece2 = h:mfWcfFfhmnN
+startFen = r8r/3nkqn3/hcb1ii1bch/1hhhhhhhh1/10/10/1HHHHHHHH1/HCB1II1BCH/3NKQN3/R8R
+#technically not needed because of initial setup
+##enPassantRegion = 0
+##castling = false
+
+#https://boardgamegeek.com/boardgame/32/buffalo-chess
+[buffalo]
+pieceToCharTable = B...D................Cb...d................c
+maxRank = 7
+maxFile = k
+customPiece1 = b:mfW
+customPiece2 = c:K
+customPiece3 = d:mQ
+startFen = bbbbbbbbbbb/11/11/11/11/3DDCDD3/11 w - - 0 1
+flagPiece = b
+flagRegionBlack = *1
+mobilityRegionWhiteCustomPiece2 = *2 *3 *4 *5 *6
+mobilityRegionWhiteCustomPiece3 = *2 *3 *4 *5 *6
+extinctionValue = loss
+extinctionPieceTypes = *
+stalemateValue = loss
+
+#https://www.zillions-of-games.com/cgi-bin/zilligames/submissions.cgi?do=show;id=1596
+[knights-halma]
+maxRank = 8
+maxFile = h
+customPiece1 = n:mN
+startFen = 5nnn/5nnn/5nnn/8/8/NNN5/NNN5/NNN5 w
+flagPiece = n
+flagRegionWhite = f8 g8 h8 f7 g7 h7 g6 g6 h8
+flagRegionBlack = a3 b3 c3 a2 b2 c2 a1 b1 c1
+flagPieceCount = 9
+stalemateValue = loss
+nFoldRule = 2
+nFoldValue = loss
+nMoveRule = 0
+
 #https://www.zillions-of-games.com/cgi-bin/zilligames/submissions.cgi/76202?do=show;id=83
 #pawns can be caught in the blast in this one
 [allexplodeatomic:nocheckatomic]