: 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) {
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);
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);
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);
}
}
}
+
+ 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)))
{
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;
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;
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);
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;
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)
{
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
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);
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);
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];
}
};
enum EnclosingRule {
- NO_ENCLOSING, REVERSI, ATAXX, QUADWRANGLE, SNORT
+ NO_ENCLOSING, REVERSI, ATAXX, QUADWRANGLE, SNORT, ANYSIDE, TOP
};
enum WallingRule {
bool capturesToHand = false;
bool firstRankPawnDrops = false;
bool promotionZonePawnDrops = false;
- bool dropOnTop = false;
EnclosingRule enclosingDrop = NO_ENCLOSING;
Bitboard enclosingDropStart = 0;
Bitboard whiteDropRegion = AllSquares;
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;
# [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: -)
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
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
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