}
if (T == EN_PASSANT)
b ^= pos.capture_square(to);
- if (pos.variant()->arrowWalling)
+
+ if (pos.walling_rule() == ARROW)
b &= moves_bb(us, type_of(pos.piece_on(from)), to, pos.pieces() ^ from);
- if ((pos.variant()->staticWalling)||(pos.variant()->duckWalling))
- b &= pos.variant()->wallingRegion[us];
- if (pos.variant()->pastWalling)
+
+ //Any current or future wall variant must follow the walling region rule if set:
+ b &= pos.variant()->wallingRegion[us];
+
+ if (pos.walling_rule() == PAST)
b &= square_bb(from);
+ if (pos.walling_rule() == EDGE)
+ {
+ Bitboard wallsquares = pos.state()->wallSquares;
+ b &= (FileABB | file_bb(pos.max_file()) | Rank1BB | rank_bb(pos.max_rank())) |
+ ( shift<NORTH >(wallsquares) | shift<SOUTH >(wallsquares)
+ | shift<EAST >(wallsquares) | shift<WEST >(wallsquares));
+ }
while (b)
*moveList++ = make_gating<T>(from, to, pt, pop_lsb(b));
return moveList;
return value == "reversi" || value == "ataxx" || value == "quadwrangle" || value =="snort" || value == "none";
}
+ template <> bool set(const std::string& value, WallingRule& target) {
+ target = value == "arrow" ? ARROW
+ : value == "duck" ? DUCK
+ : value == "edge" ? EDGE
+ : value == "past" ? PAST
+ : value == "static" ? STATIC
+ : NO_WALLING;
+ return value == "arrow" || value == "duck" || value == "edge" || value =="past" || value == "static" || value == "none";
+ }
+
template <> bool set(const std::string& value, Bitboard& target) {
char file;
int rank;
: std::is_same<T, EnclosingRule>() ? "EnclosingRule"
: std::is_same<T, Bitboard>() ? "Bitboard"
: std::is_same<T, CastlingRights>() ? "CastlingRights"
+ : std::is_same<T, WallingRule>() ? "WallingRule"
: typeid(T).name();
std::cerr << key << " - Invalid value " << it->second << " for type " << typeName << std::endl;
}
parse_attribute("dropNoDoubledCount", v->dropNoDoubledCount);
parse_attribute("immobilityIllegal", v->immobilityIllegal);
parse_attribute("gating", v->gating);
- parse_attribute("arrowWalling", v->arrowWalling);
- parse_attribute("duckWalling", v->duckWalling);
+ parse_attribute("wallingRule", v->wallingRule);
parse_attribute("wallingRegionWhite", v->wallingRegion[WHITE]);
parse_attribute("wallingRegionBlack", v->wallingRegion[BLACK]);
parse_attribute("wallingRegion", v->wallingRegion[WHITE]);
parse_attribute("wallingRegion", v->wallingRegion[BLACK]);
- parse_attribute("staticWalling", v->staticWalling);
- parse_attribute("pastWalling", v->pastWalling);
parse_attribute("seirawanGating", v->seirawanGating);
parse_attribute("cambodianMoves", v->cambodianMoves);
parse_attribute("diagonalLines", v->diagonalLines);
std::cerr << "Inconsistent settings: castlingQueensideFile > castlingKingsideFile." << std::endl;
// Check for limitations
- if (v->pieceDrops && (v->arrowWalling || v->duckWalling || v->staticWalling || v->pastWalling))
- std::cerr << "pieceDrops and arrowWalling/duckWalling are incompatible." << std::endl;
+ if (v->pieceDrops && v->wallingRule)
+ std::cerr << "pieceDrops and any walling are incompatible." << std::endl;
// Options incompatible with royal kings
if (v->pieceTypes & KING)
std::cerr << "Can not use kings with blastOnCapture." << std::endl;
if (v->flipEnclosedPieces)
std::cerr << "Can not use kings with flipEnclosedPieces." << std::endl;
- if (v->duckWalling)
- std::cerr << "Can not use kings with duckWalling." << std::endl;
+ if (v->wallingRule==DUCK)
+ std::cerr << "Can not use kings with wallingRule = duck." << std::endl;
// We can not fully check support for custom king movements at this point,
// since custom pieces are only initialized on loading of the variant.
// We will assume this is valid, but it might cause problems later if it's not.
{
Square kto = to;
Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces());
- if (var->duckWalling)
+ if (walling_rule() == DUCK)
occupied ^= st->wallSquares;
if (walling() || is_gating(m))
occupied |= gating_square(m);
return checkers() ? MoveList< EVASIONS>(*this).contains(m)
: MoveList<NON_EVASIONS>(*this).contains(m);
- // Illegal wall square placement
- if (walling() && !((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
- return false;
- if (var->arrowWalling && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
- return false;
- if (var->pastWalling && (from != gating_square(m)))
- return false;
- if ((var->staticWalling || var->duckWalling) && !(var->wallingRegion[us] & gating_square(m)))
- return false;
+ if (walling())
+ {
+ Bitboard wallsquares = st->wallSquares;
+
+ // Illegal wall square placement
+ if (!((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
+ return false;
+ if (!(var->wallingRegion[us] & gating_square(m)) || //putting a wall on disallowed square
+ wallsquares & gating_square(m)) //or square already with a wall
+ return false;
+ if (walling_rule() == ARROW && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
+ return false;
+ if (walling_rule() == PAST && (from != gating_square(m)))
+ return false;
+ if (walling_rule() == EDGE)
+ {
+ Bitboard validsquares = board_bb() &
+ ((FileABB | file_bb(max_file()) | Rank1BB | rank_bb(max_rank())) |
+ ( shift<NORTH >(wallsquares) | shift<SOUTH >(wallsquares)
+ | shift<EAST >(wallsquares) | shift<WEST >(wallsquares)));
+ if (!(validsquares & gating_square(m))) return false;
+ };
+ }
// Handle the case where a mandatory piece promotion/demotion is not taken
if ( mandatory_piece_promotion()
if (walling())
{
// Reset wall squares for duck walling
- if (var->duckWalling)
+ if (walling_rule() == DUCK)
{
Bitboard b = st->previous->wallSquares;
byTypeBB[ALL_PIECES] ^= b;
stmAttackers &= ~blockers_for_king(stm);
// Ignore distant sliders
- if (var->duckWalling)
+ if (walling_rule() == DUCK)
stmAttackers &= attacks_bb<KING>(to) | ~(pieces(BISHOP, ROOK) | pieces(QUEEN));
if (!stmAttackers)
int end = captures_to_hand() ? st->pliesFromNull : std::min(st->rule50, st->pliesFromNull);
- if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal || var->duckWalling)
+ if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal || walling_rule() == DUCK)
return false;
Key originalKey = st->key;
bool immobility_illegal() const;
bool gating() const;
bool walling() const;
+ WallingRule walling_rule() const;
bool seirawan_gating() const;
bool cambodian_moves() const;
Bitboard diagonal_lines() const;
inline bool Position::walling() const {
assert(var != nullptr);
- return var->arrowWalling || var->duckWalling || var->staticWalling || var->pastWalling;
+ return var->wallingRule != NO_WALLING;
+}
+
+inline WallingRule Position::walling_rule() const {
+ assert(var != nullptr);
+ return var->wallingRule;
}
inline bool Position::seirawan_gating() const {
continue;
// Prune moves with negative SEE (~20 Elo)
- if (!pos.variant()->duckWalling && !pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18) + 10 * !!pos.flag_region(pos.side_to_move())) * lmrDepth * lmrDepth)))
+ if (!(pos.walling_rule() == DUCK) && !pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18) + 10 * !!pos.flag_region(pos.side_to_move())) * lmrDepth * lmrDepth)))
continue;
}
}
NO_ENCLOSING, REVERSI, ATAXX, QUADWRANGLE, SNORT
};
+enum WallingRule {
+ NO_WALLING, ARROW, DUCK, EDGE, PAST, STATIC
+};
+
enum OptBool {
NO_VALUE, VALUE_FALSE, VALUE_TRUE
};
v->castlingKingPiece[WHITE] = v->castlingKingPiece[BLACK] = COMMONER;
v->extinctionValue = -VALUE_MATE;
v->extinctionPieceTypes = piece_set(COMMONER);
- v->duckWalling = true;
+ v->wallingRule = DUCK;
v->stalemateValue = VALUE_MATE;
return v;
}
v->add_piece(CUSTOM_PIECE_1, 'p', "mK"); //move as a King, but can't capture
v->startFen = "3p2/6/6/6/6/6/6/2P3 w - - 0 1";
v->stalemateValue = -VALUE_MATE;
- v->staticWalling = true;
+ v->wallingRule = STATIC;
v->wallingRegion[WHITE] = v->wallingRegion[BLACK] = AllSquares ^ make_bitboard(SQ_C1, SQ_D8);
return v;
}
v->add_piece(CUSTOM_PIECE_1, 'p', "mK"); //move as a King, but can't capture
v->startFen = "6p/7/7/7/7/7/P6 w - - 0 1";
v->stalemateValue = -VALUE_MATE;
- v->pastWalling = true;
+ v->wallingRule = PAST;
return v;
}
v->add_piece(CUSTOM_PIECE_1, 'n', "mN"); //move as a Knight, but can't capture
v->startFen = "8/8/8/4n3/3N4/8/8/8 w - - 0 1";
v->stalemateValue = -VALUE_MATE;
- v->pastWalling = true;
+ v->wallingRule = PAST;
return v;
}
v->add_piece(CUSTOM_PIECE_1, 'q', "mQ");
v->startFen = "3q2q3/10/10/q8q/10/10/Q8Q/10/10/3Q2Q3 w - - 0 1";
v->stalemateValue = -VALUE_MATE;
- v->arrowWalling = true;
+ v->wallingRule = ARROW;
return v;
}
#endif
int dropNoDoubledCount = 1;
bool immobilityIllegal = false;
bool gating = false;
- bool arrowWalling = false;
- bool duckWalling = false;
- bool staticWalling = false;
- bool pastWalling = false;
+ WallingRule wallingRule = NO_WALLING;
Bitboard wallingRegion[COLOR_NB] = {AllSquares, AllSquares};
bool seirawanGating = false;
bool cambodianMoves = false;
# [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]
+# [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)
+# - edge: edges of board, opening up new edges (ie. Atlantis)
+# - past: previous square (ie. Snailtrail)
+# - static: unchanging mask (ie. Isolation)
### Additional options relevant for usage in Winboard/XBoard
# A few options only have the purpose of improving compatibility with Winboard/Xboard.
# dropNoDoubledCount: specifies the count of already existing pieces for dropNoDoubled [int] (default: 1)
# immobilityIllegal: pieces may not move to squares where they can never move from [bool] (default: false)
# gating: maintain squares on backrank with extra rights in castling field of FEN [bool] (default: false)
-# arrowWalling: walling squares in Game of the Amazons style [bool] (default: false)
-# duckWalling: walling square in Duck chess style [bool] (default: false)
-# staticWalling: walling squares in Isolation style [bool] (default: false)
+# wallingRule: rule on where wall can be placed [WallingRule] (default: none)
# wallingRegionWhite: mask where wall squares (including duck) can be placed by white [Bitboard] (default: all squares)
# wallingRegionBlack: mask where wall squares (including duck) can be placed by black [Bitboard] (default: all squares)
-# pastWalling: walling of previous square in Snailtrail style [bool] (default: false)
# seirawanGating: allow gating of pieces in hand like in S-Chess, requires "gating = true" [bool] (default: false)
# cambodianMoves: enable special moves of cambodian chess, requires "gating = true" [bool] (default: false)
# diagonalLines: enable special moves along diagonal for specific squares (Janggi) [Bitboard]
# Atomic + duck chess hybrid.
# Playable as a custom variant in chess.com
[atomicduck:atomic]
-duckWalling = true
+wallingRule = duck
stalemateValue = win
#https://www.chessvariants.com/diffmove.dir/checkers.html
extinctionPieceTypes = kq
extinctionPseudoRoyal = true
stalemateValue = loss
+
+#https://www.chessvariants.com/boardrules.dir/atlantis.html
+[atlantis:chess]
+wallingRule = edge
+#not ready yet. Other wall variants are "move and wall", this is "move or wall".
+#need to figure out way to do this ie. write code for:
+#wallOrMove = true
\ No newline at end of file