Skip to content

Commit

Permalink
add Edge Walling rule, suggesting refactor of Walling Rule, (#722)
Browse files Browse the repository at this point in the history
  • Loading branch information
RainRat authored Sep 21, 2023
1 parent 1b5a789 commit 994eb7b
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 41 deletions.
18 changes: 14 additions & 4 deletions src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,23 @@ namespace {
}
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;
Expand Down
24 changes: 16 additions & 8 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ namespace {
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;
Expand Down Expand Up @@ -181,6 +191,7 @@ template <bool Current, class T> bool VariantParser<DoCheck>::parse_attribute(co
: 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;
}
Expand Down Expand Up @@ -434,14 +445,11 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
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);
Expand Down Expand Up @@ -553,8 +561,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
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)
Expand All @@ -563,8 +571,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
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.
Expand Down
40 changes: 27 additions & 13 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ bool Position::legal(Move m) const {
{
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);
Expand Down Expand Up @@ -1303,15 +1303,29 @@ bool Position::pseudo_legal(const Move m) const {
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()
Expand Down Expand Up @@ -2034,7 +2048,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
if (walling())
{
// Reset wall squares for duck walling
if (var->duckWalling)
if (walling_rule() == DUCK)
{
Bitboard b = st->previous->wallSquares;
byTypeBB[ALL_PIECES] ^= b;
Expand Down Expand Up @@ -2476,7 +2490,7 @@ bool Position::see_ge(Move m, Value threshold) const {
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)
Expand Down Expand Up @@ -2969,7 +2983,7 @@ bool Position::has_game_cycle(int ply) const {

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;
Expand Down
8 changes: 7 additions & 1 deletion src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ class Position {
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;
Expand Down Expand Up @@ -761,7 +762,12 @@ inline bool Position::gating() 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 {
Expand Down
2 changes: 1 addition & 1 deletion src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1185,7 +1185,7 @@ namespace {
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;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ enum EnclosingRule {
NO_ENCLOSING, REVERSI, ATAXX, QUADWRANGLE, SNORT
};

enum WallingRule {
NO_WALLING, ARROW, DUCK, EDGE, PAST, STATIC
};

enum OptBool {
NO_VALUE, VALUE_FALSE, VALUE_TRUE
};
Expand Down
10 changes: 5 additions & 5 deletions src/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ namespace {
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;
}
Expand All @@ -529,7 +529,7 @@ namespace {
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;
}
Expand All @@ -551,7 +551,7 @@ namespace {
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;
}

Expand All @@ -562,7 +562,7 @@ namespace {
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;
}

Expand Down Expand Up @@ -1668,7 +1668,7 @@ namespace {
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
Expand Down
5 changes: 1 addition & 4 deletions src/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,7 @@ struct Variant {
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;
Expand Down
20 changes: 15 additions & 5 deletions src/variants.ini
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,12 @@
# [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.
Expand Down Expand Up @@ -213,12 +219,9 @@
# 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]
Expand Down Expand Up @@ -1349,7 +1352,7 @@ pieceToCharTable = P...Q..AH..ECTDY....LKp...q..ah..ectdy....lk
# 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
Expand Down Expand Up @@ -1769,3 +1772,10 @@ extinctionValue = loss
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

0 comments on commit 994eb7b

Please sign in to comment.