For some games like Ataxx and Othello, specifying the pieces in hand is unnecessary. Setting freeDrops to true removes this from the FEN string.
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)
// 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<T>(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<T>(from, to, pt_gating, to);
return moveList;
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);
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);
if (pt != PAWN && pt != KING)
moveList = generate_moves<Us, Checks>(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<Us, Type>(pos, moveList, pt, target & ~pos.pieces(~Us));
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)
}
// pieces in hand
- if (piece_drops() || seirawan_gating() || arrow_gating())
+ if (!variant()->freeDrops && (piece_drops() || seirawan_gating() || arrow_gating()))
{
ss << '[';
if (holdings != "-")
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))));
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;
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 {
}
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);
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
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;
v->flipEnclosedPieces = ATAXX;
v->materialCounting = UNWEIGHTED_MATERIAL;
v->nMoveRule = 0;
+ v->freeDrops = true;
return v;
}
// Flipersi
bool flyingGeneral = false;
Rank soldierPromotionRank = RANK_1;
EnclosingRule flipEnclosedPieces = NO_ENCLOSING;
+ bool freeDrops = false;
// game end
int nMoveRule = 50;
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