From: kz04px <6536046+kz04px@users.noreply.github.com> Date: Tue, 24 May 2022 21:58:22 +0000 (+0100) Subject: Implement Variant::freeDrops (#486) X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=c78a566635f798e0ee602cf708e975aee652a5ed;p=fairystockfish.git Implement Variant::freeDrops (#486) For some games like Ataxx and Othello, specifying the pieces in hand is unnecessary. Setting freeDrops to true removes this from the FEN string. --- diff --git a/src/movegen.cpp b/src/movegen.cpp index 57d647d..ee9039a 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -32,7 +32,7 @@ namespace { if (pos.arrow_gating()) { for (PieceType pt_gating : pos.piece_types()) - if (pos.count_in_hand(us, pt_gating) > 0) + if (pos.can_drop(us, pt_gating)) { Bitboard b = pos.drop_region(us, pt_gating) & moves_bb(us, type_of(pos.piece_on(from)), to, pos.pieces() ^ from) & ~(pos.pieces() ^ from); while (b) @@ -46,11 +46,11 @@ namespace { // Gating moves if (pos.seirawan_gating() && (pos.gates(us) & from)) for (PieceType pt_gating : pos.piece_types()) - if (pos.count_in_hand(us, pt_gating) > 0 && (pos.drop_region(us, pt_gating) & from)) + if (pos.can_drop(us, pt_gating) && (pos.drop_region(us, pt_gating) & from)) *moveList++ = make_gating(from, to, pt_gating, from); if (pos.seirawan_gating() && T == CASTLING && (pos.gates(us) & to)) for (PieceType pt_gating : pos.piece_types()) - if (pos.count_in_hand(us, pt_gating) > 0 && (pos.drop_region(us, pt_gating) & to)) + if (pos.can_drop(us, pt_gating) && (pos.drop_region(us, pt_gating) & to)) *moveList++ = make_gating(from, to, pt_gating, to); return moveList; @@ -76,7 +76,7 @@ namespace { ExtMove* generate_drops(const Position& pos, ExtMove* moveList, PieceType pt, Bitboard b) { assert(Type != CAPTURES); // Do not generate virtual drops for perft and at root - if (pos.count_in_hand(Us, pt) > 0 || (Type != NON_EVASIONS && pos.two_boards() && pos.allow_virtual_drop(Us, pt))) + if (pos.can_drop(Us, pt) || (Type != NON_EVASIONS && pos.two_boards() && pos.allow_virtual_drop(Us, pt))) { // Restrict to valid target b &= pos.drop_region(Us, pt); @@ -90,7 +90,7 @@ namespace { while (b2) *moveList++ = make_drop(pop_lsb(b2), pt, pos.promoted_piece_type(pt)); } - if (Type == QUIET_CHECKS || pos.count_in_hand(Us, pt) <= 0) + if (Type == QUIET_CHECKS || !pos.can_drop(Us, pt)) b &= pos.check_squares(pt); while (b) *moveList++ = make_drop(pop_lsb(b), pt, pt); @@ -342,7 +342,7 @@ namespace { if (pt != PAWN && pt != KING) moveList = generate_moves(pos, moveList, pt, target); // generate drops - if (pos.piece_drops() && Type != CAPTURES && (pos.count_in_hand(Us, ALL_PIECES) > 0 || pos.two_boards())) + if (pos.piece_drops() && Type != CAPTURES && (pos.can_drop(Us, ALL_PIECES) || pos.two_boards())) for (PieceType pt : pos.piece_types()) moveList = generate_drops(pos, moveList, pt, target & ~pos.pieces(~Us)); diff --git a/src/position.cpp b/src/position.cpp index 14dc975..1e0d2fc 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -72,7 +72,7 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) { os << " *"; else os << " "; - if (pos.piece_drops() || pos.seirawan_gating() || pos.arrow_gating()) + if (!pos.variant()->freeDrops && (pos.piece_drops() || pos.seirawan_gating() || pos.arrow_gating())) { os << " ["; for (PieceType pt = KING; pt >= PAWN; --pt) @@ -693,7 +693,7 @@ string Position::fen(bool sfen, bool showPromoted, int countStarted, std::string } // pieces in hand - if (piece_drops() || seirawan_gating() || arrow_gating()) + if (!variant()->freeDrops && (piece_drops() || seirawan_gating() || arrow_gating())) { ss << '['; if (holdings != "-") @@ -1164,7 +1164,7 @@ bool Position::pseudo_legal(const Move m) const { return piece_drops() && pc != NO_PIECE && color_of(pc) == us - && (count_in_hand(us, in_hand_piece_type(m)) > 0 || (two_boards() && allow_virtual_drop(us, type_of(pc)))) + && (can_drop(us, in_hand_piece_type(m)) || (two_boards() && allow_virtual_drop(us, type_of(pc)))) && (drop_region(us, type_of(pc)) & ~pieces() & to) && ( type_of(pc) == in_hand_piece_type(m) || (drop_promoted() && type_of(pc) == promoted_piece_type(in_hand_piece_type(m)))); diff --git a/src/position.h b/src/position.h index 30c73a4..f06566c 100644 --- a/src/position.h +++ b/src/position.h @@ -161,6 +161,7 @@ public: 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; Bitboard drop_region(Color c, PieceType pt) const; @@ -1214,7 +1215,7 @@ inline bool Position::capture(Move m) const { inline bool Position::virtual_drop(Move m) const { assert(is_ok(m)); - return type_of(m) == DROP && count_in_hand(side_to_move(), in_hand_piece_type(m)) <= 0; + return type_of(m) == DROP && !can_drop(side_to_move(), in_hand_piece_type(m)); } inline Piece Position::captured_piece() const { @@ -1340,19 +1341,21 @@ inline Value Position::material_counting_result() const { } inline void Position::add_to_hand(Piece pc) { + if (variant()->freeDrops) return; pieceCountInHand[color_of(pc)][type_of(pc)]++; pieceCountInHand[color_of(pc)][ALL_PIECES]++; psq += PSQT::psq[pc][SQ_NONE]; } inline void Position::remove_from_hand(Piece pc) { + if (variant()->freeDrops) return; pieceCountInHand[color_of(pc)][type_of(pc)]--; pieceCountInHand[color_of(pc)][ALL_PIECES]--; psq -= PSQT::psq[pc][SQ_NONE]; } inline void Position::drop_piece(Piece pc_hand, Piece pc_drop, Square s) { - assert(pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)] > 0 || var->twoBoards); + assert(can_drop(color_of(pc_hand), type_of(pc_hand)) || var->twoBoards); put_piece(pc_drop, s, pc_drop != pc_hand, pc_drop != pc_hand ? pc_hand : NO_PIECE); remove_from_hand(pc_hand); virtualPieces += (pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)] < 0); @@ -1363,7 +1366,11 @@ inline void Position::undrop_piece(Piece pc_hand, Square s) { remove_piece(s); board[s] = NO_PIECE; add_to_hand(pc_hand); - assert(pieceCountInHand[color_of(pc_hand)][type_of(pc_hand)] > 0 || var->twoBoards); + assert(can_drop(color_of(pc_hand), type_of(pc_hand)) || var->twoBoards); +} + +inline bool Position::can_drop(Color c, PieceType pt) const { + return variant()->freeDrops || count_in_hand(c, pt) > 0; } } // namespace Stockfish diff --git a/src/variant.cpp b/src/variant.cpp index 4d64c71..632272e 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -857,7 +857,7 @@ namespace { v->maxFile = FILE_G; v->reset_pieces(); v->add_piece(CUSTOM_PIECES, 'p', "mDmNmA"); - v->startFen = "P5p/7/7/7/7/7/p5P[PPPPPPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppppppp] w 0 1"; + v->startFen = "P5p/7/7/7/7/7/p5P w 0 1"; v->promotionPieceTypes = {}; v->pieceDrops = true; v->doubleStep = false; @@ -870,6 +870,7 @@ namespace { v->flipEnclosedPieces = ATAXX; v->materialCounting = UNWEIGHTED_MATERIAL; v->nMoveRule = 0; + v->freeDrops = true; return v; } // Flipersi diff --git a/src/variant.h b/src/variant.h index 65fb1f6..aba01a7 100644 --- a/src/variant.h +++ b/src/variant.h @@ -105,6 +105,7 @@ struct Variant { bool flyingGeneral = false; Rank soldierPromotionRank = RANK_1; EnclosingRule flipEnclosedPieces = NO_ENCLOSING; + bool freeDrops = false; // game end int nMoveRule = 50; diff --git a/tests/perft.sh b/tests/perft.sh index c87a7f5..9f00fa7 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -114,7 +114,7 @@ if [[ $1 == "all" || $1 == "variant" ]]; then expect perft.exp torishogi startpos 4 103857 > /dev/null # non-chess expect perft.exp ataxx startpos 4 155888 > /dev/null - expect perft.exp ataxx "fen 7/7/7/7/ppppppp/ppppppp/PPPPPPP[PPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppp] w 0 1" 5 452980 > /dev/null + expect perft.exp ataxx "fen 7/7/7/7/ppppppp/ppppppp/PPPPPPP w 0 1" 5 452980 > /dev/null expect perft.exp breakthrough startpos 4 256036 > /dev/null expect perft.exp breakthrough "fen 1p2pp1p/2p2ppp/2P5/8/8/3P2P1/1p1P2PP/1PP1PP1P w - - 1 26" 4 121264 > /dev/null expect perft.exp clobber startpos 3 80063 > /dev/null