From: RainRat Date: Wed, 6 Sep 2023 07:34:28 +0000 (-0700) Subject: add Duck region mask. add forward/checkers (#705) X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=60953929ca5ca691e5fb9bbb32bb56afd50d68a8;p=fairystockfish.git add Duck region mask. add forward/checkers (#705) --- diff --git a/src/apiutil.h b/src/apiutil.h index ca5858e..0794abc 100644 --- a/src/apiutil.h +++ b/src/apiutil.h @@ -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 diff --git a/src/movegen.cpp b/src/movegen.cpp index b33d986..0c14dd7 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -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) @@ -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) diff --git a/src/parser.cpp b/src/parser.cpp index 348f17f..4b07440 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -410,11 +410,14 @@ Variant* VariantParser::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); @@ -525,8 +528,8 @@ Variant* VariantParser::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) @@ -535,8 +538,8 @@ Variant* VariantParser::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. diff --git a/src/position.cpp b/src/position.cpp index 1b8ae90..a87ce1d 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -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) { @@ -1296,15 +1296,15 @@ bool Position::pseudo_legal(const Move m) const { : MoveList(*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) @@ -1803,7 +1803,7 @@ 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)]; @@ -1811,7 +1811,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { 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)]; @@ -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; @@ -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(to) | ~(pieces(BISHOP, ROOK) | pieces(QUEEN)); if (!stmAttackers) @@ -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; diff --git a/src/position.h b/src/position.h index fcdd6ca..2279135 100644 --- a/src/position.h +++ b/src/position.h @@ -178,7 +178,7 @@ public: 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; @@ -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 { diff --git a/src/search.cpp b/src/search.cpp index 38d72f5..2502fcc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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 @@ -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; @@ -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); } @@ -1185,7 +1185,7 @@ moves_loop: // When in check, search starts from here 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; } } @@ -1823,9 +1823,9 @@ moves_loop: // When in check, search starts from here // 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); } @@ -1834,7 +1834,7 @@ moves_loop: // When in check, search starts from here { // 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; } @@ -1849,9 +1849,9 @@ moves_loop: // When in check, search starts from here { 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; } } @@ -1887,7 +1887,7 @@ moves_loop: // When in check, search starts from here 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); diff --git a/src/uci.cpp b/src/uci.cpp index 9902afd..584977a 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -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) @@ -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; diff --git a/src/variant.cpp b/src/variant.cpp index a0ce815..311651c 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -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; } @@ -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; } @@ -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; } @@ -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; } @@ -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; } @@ -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 diff --git a/src/variant.h b/src/variant.h index 0492dcc..37de420 100644 --- a/src/variant.h +++ b/src/variant.h @@ -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; diff --git a/src/variants.ini b/src/variants.ini index 60c701c..71cb8d2 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -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] @@ -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