Skip to content

Commit

Permalink
add Duck region mask. add forward/checkers (fairy-stockfish#705)
Browse files Browse the repository at this point in the history
  • Loading branch information
RainRat authored Sep 6, 2023
1 parent a080a67 commit 6095392
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 63 deletions.
2 changes: 1 addition & 1 deletion src/apiutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ inline const std::string move_to_san(Position& pos, Move m, Notation n) {
}

// Wall square
if (pos.wall_gating())
if (pos.walling())
san += "," + square(pos, gating_square(m), n);

// Check and checkmate
Expand Down
10 changes: 5 additions & 5 deletions src/movegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace {
ExtMove* make_move_and_gating(const Position& pos, ExtMove* moveList, Color us, Square from, Square to, PieceType pt = NO_PIECE_TYPE) {

// Wall placing moves
if (pos.wall_gating())
if (pos.walling())
{
Bitboard b = pos.board_bb() & ~((pos.pieces() ^ from) | to);
if (T == CASTLING)
Expand All @@ -41,11 +41,11 @@ namespace {
}
if (T == EN_PASSANT)
b ^= pos.capture_square(to);
if (pos.variant()->arrowGating)
if (pos.variant()->arrowWalling)
b &= moves_bb(us, type_of(pos.piece_on(from)), to, pos.pieces() ^ from);
if (pos.variant()->staticGating)
b &= pos.variant()->staticGatingRegion;
if (pos.variant()->pastGating)
if ((pos.variant()->staticWalling)||(pos.variant()->duckWalling))
b &= pos.variant()->wallingRegion[us];
if (pos.variant()->pastWalling)
b &= square_bb(from);

while (b)
Expand Down
21 changes: 12 additions & 9 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,14 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
parse_attribute("dropNoDoubledCount", v->dropNoDoubledCount);
parse_attribute("immobilityIllegal", v->immobilityIllegal);
parse_attribute("gating", v->gating);
parse_attribute("arrowGating", v->arrowGating);
parse_attribute("duckGating", v->duckGating);
parse_attribute("staticGating", v->staticGating);
parse_attribute("pastGating", v->pastGating);
parse_attribute("staticGatingRegion", v->staticGatingRegion);
parse_attribute("arrowWalling", v->arrowWalling);
parse_attribute("duckWalling", v->duckWalling);
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 @@ -525,8 +528,8 @@ Variant* VariantParser<DoCheck>::parse(Variant* v) {
std::cerr << "Inconsistent settings: castlingQueensideFile > castlingKingsideFile." << std::endl;

// Check for limitations
if (v->pieceDrops && (v->arrowGating || v->duckGating || v->staticGating || v->pastGating))
std::cerr << "pieceDrops and arrowGating/duckGating are incompatible." << std::endl;
if (v->pieceDrops && (v->arrowWalling || v->duckWalling || v->staticWalling || v->pastWalling))
std::cerr << "pieceDrops and arrowWalling/duckWalling are incompatible." << std::endl;

// Options incompatible with royal kings
if (v->pieceTypes & KING)
Expand All @@ -535,8 +538,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->duckGating)
std::cerr << "Can not use kings with duckGating." << std::endl;
if (v->duckWalling)
std::cerr << "Can not use kings with duckWalling." << 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
28 changes: 14 additions & 14 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,9 +1099,9 @@ bool Position::legal(Move m) const {
{
Square kto = to;
Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces());
if (var->duckGating)
if (var->duckWalling)
occupied ^= st->wallSquares;
if (wall_gating() || is_gating(m))
if (walling() || is_gating(m))
occupied |= gating_square(m);
if (type_of(m) == CASTLING)
{
Expand Down Expand Up @@ -1296,15 +1296,15 @@ bool Position::pseudo_legal(const Move m) const {
: MoveList<NON_EVASIONS>(*this).contains(m);

// Illegal wall square placement
if (wall_gating() && !((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
if (walling() && !((board_bb() & ~((pieces() ^ from) | to)) & gating_square(m)))
return false;
if (var->arrowGating && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
if (var->arrowWalling && !(moves_bb(us, type_of(pc), to, pieces() ^ from) & gating_square(m)))
return false;
if (var->pastGating && (from != gating_square(m)))
if (var->pastWalling && (from != gating_square(m)))
return false;
if (var->staticGating && !(var->staticGatingRegion & gating_square(m)))
if ((var->staticWalling || var->duckWalling) && !(var->wallingRegion[us] & gating_square(m)))
return false;

// Handle the case where a mandatory piece promotion/demotion is not taken
if ( mandatory_piece_promotion()
&& (is_promoted(from) ? piece_demotion() : promoted_piece_type(type_of(pc)) != NO_PIECE_TYPE)
Expand Down Expand Up @@ -1803,15 +1803,15 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
{
if ( (var->enPassantRegion & (to - pawn_push(us)))
&& ((pawn_attacks_bb(us, to - pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN))
&& !(wall_gating() && gating_square(m) == to - pawn_push(us)))
&& !(walling() && gating_square(m) == to - pawn_push(us)))
{
st->epSquares |= to - pawn_push(us);
k ^= Zobrist::enpassant[file_of(to)];
}
if ( std::abs(int(to) - int(from)) == 3 * NORTH
&& (var->enPassantRegion & (to - 2 * pawn_push(us)))
&& ((pawn_attacks_bb(us, to - 2 * pawn_push(us)) & pieces(them, PAWN)) || var->enPassantTypes[them] & ~piece_set(PAWN))
&& !(wall_gating() && gating_square(m) == to - 2 * pawn_push(us)))
&& !(walling() && gating_square(m) == to - 2 * pawn_push(us)))
{
st->epSquares |= to - 2 * pawn_push(us);
k ^= Zobrist::enpassant[file_of(to)];
Expand Down Expand Up @@ -2016,10 +2016,10 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
}

// Add gated wall square
if (wall_gating())
if (walling())
{
// Reset wall squares for duck gating
if (var->duckGating)
// Reset wall squares for duck walling
if (var->duckWalling)
{
Bitboard b = st->previous->wallSquares;
byTypeBB[ALL_PIECES] ^= b;
Expand Down Expand Up @@ -2457,7 +2457,7 @@ bool Position::see_ge(Move m, Value threshold) const {
stmAttackers &= ~blockers_for_king(stm);

// Ignore distant sliders
if (var->duckGating)
if (var->duckWalling)
stmAttackers &= attacks_bb<KING>(to) | ~(pieces(BISHOP, ROOK) | pieces(QUEEN));

if (!stmAttackers)
Expand Down Expand Up @@ -2924,7 +2924,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->duckGating)
if (end < 3 || var->nFoldValue != VALUE_DRAW || var->perpetualCheckIllegal || var->materialCounting || var->moveRepetitionIllegal || var->duckWalling)
return false;

Key originalKey = st->key;
Expand Down
6 changes: 3 additions & 3 deletions src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class Position {
PieceType drop_no_doubled() const;
bool immobility_illegal() const;
bool gating() const;
bool wall_gating() const;
bool walling() const;
bool seirawan_gating() const;
bool cambodian_moves() const;
Bitboard diagonal_lines() const;
Expand Down Expand Up @@ -753,9 +753,9 @@ inline bool Position::gating() const {
return var->gating;
}

inline bool Position::wall_gating() const {
inline bool Position::walling() const {
assert(var != nullptr);
return var->arrowGating || var->duckGating || var->staticGating || var->pastGating;
return var->arrowWalling || var->duckWalling || var->staticWalling || var->pastWalling;
}

inline bool Position::seirawan_gating() const {
Expand Down
20 changes: 10 additions & 10 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace {
}

int futility_move_count(bool improving, Depth depth, const Position& pos) {
return (3 + depth * depth * (1 + pos.wall_gating()) + 2 * pos.blast_on_capture()) / (2 - improving + pos.blast_on_capture());
return (3 + depth * depth * (1 + pos.walling()) + 2 * pos.blast_on_capture()) / (2 - improving + pos.blast_on_capture());
}

// History and stats update bonus, based on depth
Expand Down Expand Up @@ -281,7 +281,7 @@ void MainThread::search() {
if (!Limits.infinite && !ponder && rootMoves[0].pv[0] != MOVE_NONE && !Threads.abort.exchange(true))
{
std::string move = UCI::move(rootPos, bestMove);
if (rootPos.wall_gating())
if (rootPos.walling())
{
sync_cout << "move " << move.substr(0, move.find(",")) << "," << sync_endl;
sync_cout << "move " << move.substr(move.find(",") + 1) << sync_endl;
Expand Down Expand Up @@ -800,7 +800,7 @@ namespace {
{
int penalty = -stat_bonus(depth);
thisThread->mainHistory[us][from_to(ttMove)] << penalty;
if (pos.wall_gating())
if (pos.walling())
thisThread->gateHistory[us][gating_square(ttMove)] << penalty;
update_continuation_histories(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty);
}
Expand Down Expand Up @@ -1185,7 +1185,7 @@ namespace {
continue;

// Prune moves with negative SEE (~20 Elo)
if (!pos.variant()->duckGating && !pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18) + 10 * !!pos.flag_region(pos.side_to_move())) * lmrDepth * lmrDepth)))
if (!pos.variant()->duckWalling && !pos.see_ge(move, Value(-(30 - std::min(lmrDepth, 18) + 10 * !!pos.flag_region(pos.side_to_move())) * lmrDepth * lmrDepth)))
continue;
}
}
Expand Down Expand Up @@ -1823,9 +1823,9 @@ namespace {
// Decrease stats for all non-best quiet moves
for (int i = 0; i < quietCount; ++i)
{
if (!(pos.wall_gating() && from_to(quietsSearched[i]) == from_to(bestMove)))
if (!(pos.walling() && from_to(quietsSearched[i]) == from_to(bestMove)))
thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bonus2;
if (pos.wall_gating())
if (pos.walling())
thisThread->gateHistory[us][gating_square(quietsSearched[i])] << -bonus2;
update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]), to_sq(quietsSearched[i]), -bonus2);
}
Expand All @@ -1834,7 +1834,7 @@ namespace {
{
// Increase stats for the best move in case it was a capture move
captureHistory[moved_piece][to_sq(bestMove)][captured] << bonus1;
if (pos.wall_gating())
if (pos.walling())
thisThread->gateHistory[us][gating_square(bestMove)] << bonus1;
}

Expand All @@ -1849,9 +1849,9 @@ namespace {
{
moved_piece = pos.moved_piece(capturesSearched[i]);
captured = type_of(pos.piece_on(to_sq(capturesSearched[i])));
if (!(pos.wall_gating() && from_to(capturesSearched[i]) == from_to(bestMove)))
if (!(pos.walling() && from_to(capturesSearched[i]) == from_to(bestMove)))
captureHistory[moved_piece][to_sq(capturesSearched[i])][captured] << -bonus1;
if (pos.wall_gating())
if (pos.walling())
thisThread->gateHistory[us][gating_square(capturesSearched[i])] << -bonus1;
}
}
Expand Down Expand Up @@ -1887,7 +1887,7 @@ namespace {
Color us = pos.side_to_move();
Thread* thisThread = pos.this_thread();
thisThread->mainHistory[us][from_to(move)] << bonus;
if (pos.wall_gating())
if (pos.walling())
thisThread->gateHistory[us][gating_square(move)] << bonus;
update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus);

Expand Down
4 changes: 2 additions & 2 deletions src/uci.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ string UCI::move(const Position& pos, Move m) {
: UCI::square(pos, from)) + UCI::square(pos, to);

// Wall square
if (pos.wall_gating() && CurrentProtocol == XBOARD)
if (pos.walling() && CurrentProtocol == XBOARD)
move += "," + UCI::square(pos, to) + UCI::square(pos, gating_square(m));

if (type_of(m) == PROMOTION)
Expand All @@ -552,7 +552,7 @@ string UCI::move(const Position& pos, Move m) {
}

// Wall square
if (pos.wall_gating() && CurrentProtocol != XBOARD)
if (pos.walling() && CurrentProtocol != XBOARD)
move += "," + UCI::square(pos, to) + UCI::square(pos, gating_square(m));

return move;
Expand Down
16 changes: 8 additions & 8 deletions src/variant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ namespace {
v->castlingKingPiece[WHITE] = v->castlingKingPiece[BLACK] = COMMONER;
v->extinctionValue = -VALUE_MATE;
v->extinctionPieceTypes = piece_set(COMMONER);
v->duckGating = true;
v->duckWalling = true;
v->stalemateValue = VALUE_MATE;
return v;
}
Expand All @@ -512,10 +512,10 @@ namespace {
v->maxFile = FILE_F;
v->reset_pieces();
v->add_piece(CUSTOM_PIECE_1, 'p', "mK"); //move as a King, but can't capture
v->startFen = "2p3/6/6/6/6/6/6/3P2 w - - 0 1";
v->startFen = "3p2/6/6/6/6/6/6/2P3 w - - 0 1";
v->stalemateValue = -VALUE_MATE;
v->staticGating = true;
v->staticGatingRegion = AllSquares ^ make_bitboard(SQ_C1, SQ_D8);
v->staticWalling = true;
v->wallingRegion[WHITE] = v->wallingRegion[BLACK] = AllSquares ^ make_bitboard(SQ_C1, SQ_D8);
return v;
}

Expand All @@ -524,7 +524,7 @@ namespace {
v->maxRank = RANK_7;
v->maxFile = FILE_G;
v->startFen = "3p3/7/7/7/7/7/3P3 w - - 0 1";
v->staticGatingRegion = AllSquares ^ make_bitboard(SQ_D1, SQ_D7);
v->wallingRegion[WHITE] = v->wallingRegion[BLACK] = AllSquares ^ make_bitboard(SQ_D1, SQ_D7);
return v;
}

Expand All @@ -536,7 +536,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->pastGating = true;
v->pastWalling = true;
return v;
}

Expand All @@ -547,7 +547,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->pastGating = true;
v->pastWalling = true;
return v;
}

Expand Down Expand Up @@ -1653,7 +1653,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->arrowGating = true;
v->arrowWalling = true;
return v;
}
#endif
Expand Down
10 changes: 5 additions & 5 deletions src/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ struct Variant {
int dropNoDoubledCount = 1;
bool immobilityIllegal = false;
bool gating = false;
bool arrowGating = false;
bool duckGating = false;
bool staticGating = false;
bool pastGating = false;
Bitboard staticGatingRegion = AllSquares;
bool arrowWalling = false;
bool duckWalling = false;
bool staticWalling = false;
bool pastWalling = false;
Bitboard wallingRegion[COLOR_NB] = {AllSquares, AllSquares};
bool seirawanGating = false;
bool cambodianMoves = false;
Bitboard diagonalLines = 0;
Expand Down
31 changes: 25 additions & 6 deletions src/variants.ini
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,12 @@
# 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)
# arrowGating: gating of wall squares in Game of the Amazons style [bool] (default: false)
# duckGating: gating of a wall square in Duck chess style [bool] (default: false)
# staticGating: gating of wall squares in Isolation style [bool] (default: false)
# staticGatingRegion: mask where wall squares can be placed [Bitboard] (default: all squares)
# pastGating: gating of previous square [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)
# 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 @@ -1345,9 +1346,27 @@ pieceToCharTable = P...Q..AH..ECTDY....LKp...q..ah..ectdy....lk
# Atomic + duck chess hybrid.
# Playable as a custom variant in chess.com
[atomicduck:atomic]
duckGating = true
duckWalling = true
stalemateValue = win

#https://www.chessvariants.com/diffmove.dir/checkers.html
[forward:chess]
pieceToCharTable = PNBRQGE......S.F..LKpnbrqge......s.f..lk
#pieces move only forward. Not even sideways, so no castling.
castling = false
#I tried to pick letters that would remind people of the full piece.
startFen = lesfgsel/pppppppp/8/8/8/8/PPPPPPPP/LESFGSEL w KQkq - 0 1
lance = l
customPiece1 = g:fFfW
customPiece2 = e:ffNfsN
customPiece3 = s:fB
customPiece4 = f:fBfR
promotedPieceType = l:r e:n s:b f:q g:k
#since the king changes forms, should be an extinction variant
extinctionValue = loss
extinctionPieceTypes = kg
extinctionPseudoRoyal = true

[kono]
maxRank = 5
maxFile = e
Expand Down

0 comments on commit 6095392

Please sign in to comment.