Simplify en passant square update in Position::do_move().

Passed non-regression STC:

LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 119680 W: 31011 L: 30884 D: 57785
Ptnml(0-2): 354, 13231, 32575, 13294, 386
https://tests.stockfishchess.org/tests/view/6973b06c6cd60a8e97ca62e5

closes https://github.com/official-stockfish/Stockfish/pull/6565

No functional change
This commit is contained in:
Pieter te Brake
2026-02-04 18:17:23 +01:00
committed by Joost VandeVondele
parent 9f42980dd2
commit 2321cf2f77
2 changed files with 33 additions and 69 deletions
+32 -69
View File
@@ -273,19 +273,19 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si) {
Bitboard pawns = attacks_bb<PAWN>(st->epSquare, ~sideToMove) & pieces(sideToMove, PAWN);
Bitboard target = (pieces(~sideToMove, PAWN) & (st->epSquare + pawn_push(~sideToMove)));
Bitboard occ = pieces() ^ target ^ st->epSquare;
Bitboard occ = pieces() ^ target ^ st->epSquare;
// En passant square will be considered only if
// a) side to move have a pawn threatening epSquare
// b) there is an enemy pawn in front of epSquare
// c) there is no piece on epSquare or behind epSquare
enpassant = pawns
&& target
&& !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove))));
enpassant =
pawns && target && !(pieces() & (st->epSquare | (st->epSquare + pawn_push(sideToMove))));
// If no pawn can execute the en passant capture without leaving the king in check, don't record the epSquare
while (pawns)
legalEP |= !(attackers_to(square<KING>(sideToMove), occ ^ pop_lsb(pawns)) & pieces(~sideToMove) & ~target);
legalEP |= !(attackers_to(square<KING>(sideToMove), occ ^ pop_lsb(pawns))
& pieces(~sideToMove) & ~target);
}
if (!enpassant || !legalEP)
@@ -739,8 +739,6 @@ void Position::do_move(Move m,
Piece pc = piece_on(from);
Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
bool checkEP = false;
dp.pc = pc;
dp.from = from;
dp.to = to;
@@ -844,9 +842,30 @@ void Position::do_move(Move m,
// If the moving piece is a pawn do some special extra work
if (type_of(pc) == PAWN)
{
// Check later if the en passant square needs to be set
// Check if the en passant square needs to be set. Accurate e.p. info is needed
// for correct zobrist key generation and 3-fold checking.
if ((int(to) ^ int(from)) == 16)
checkEP = true;
{
Square epSquare = to - pawn_push(us);
Bitboard pawns = attacks_bb<PAWN>(epSquare, us) & pieces(them, PAWN);
// If there are no pawns attacking the ep square, ep is not possible.
if (pawns)
{
Square ksq = square<KING>(them);
Bitboard notBlockers = ~st->previous->blockersForKing[them];
bool noDiscovery = (from & notBlockers) || file_of(from) == file_of(ksq);
// If the pawn gives discovered check, ep is never legal. Else, if at least one
// pawn was not a blocker for the enemy king or lies on the same line as the
// enemy king and en passant square, a legal capture exists.
if (noDiscovery && (pawns & (notBlockers | line_bb(epSquare, ksq))))
{
st->epSquare = epSquare;
k ^= Zobrist::enpassant[file_of(epSquare)];
}
}
}
else if (m.type_of() == PROMOTION)
{
@@ -891,9 +910,10 @@ void Position::do_move(Move m,
st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
}
// If en passant is impossible, then k will not change and we can prefetch earlier
if (tt && !checkEP)
prefetch(tt->first_entry(adjust_key50(k)));
// Update the key with the final value
st->key = k;
if (tt)
prefetch(tt->first_entry(key()));
if (history)
{
@@ -915,63 +935,6 @@ void Position::do_move(Move m,
// Update king attacks used for fast check detection
set_check_info();
// Accurate e.p. info is needed for correct zobrist key generation and 3-fold checking
while (checkEP)
{
auto updateEpSquare = [&] {
st->epSquare = to - pawn_push(us);
k ^= Zobrist::enpassant[file_of(st->epSquare)];
};
Bitboard pawns = attacks_bb<PAWN>(to - pawn_push(us), us) & pieces(them, PAWN);
// If there are no pawns attacking the ep square, ep is not possible
if (!pawns)
break;
// If there are checkers other than the to be captured pawn, ep is never legal
if (checkers() & ~square_bb(to))
break;
if (more_than_one(pawns))
{
// If there are two pawns potentially being able to capture and at least one
// is not pinned, ep is legal as there are no horizontal exposed checks
if (!more_than_one(blockers_for_king(them) & pawns))
{
updateEpSquare();
break;
}
// If there is no pawn on our king's file, and thus both pawns are pinned
// by bishops, ep is not legal as the king square must be in front of the to square.
// And because the ep square and the king are not on a common diagonal, either ep capture
// would expose the king to a check from one of the bishops
if (!(file_bb(square<KING>(them)) & pawns))
break;
// Otherwise remove the pawn on the king file, as an ep capture by it can never be legal and the
// check below relies on there only being one pawn
pawns &= ~file_bb(square<KING>(them));
}
Square ksq = square<KING>(them);
Square capsq = to;
Bitboard occupied = (pieces() ^ lsb(pawns) ^ capsq) | (to - pawn_push(us));
// If our king is not attacked after making the move, ep is legal.
if (!(attacks_bb<ROOK>(ksq, occupied) & pieces(us, QUEEN, ROOK))
&& !(attacks_bb<BISHOP>(ksq, occupied) & pieces(us, QUEEN, BISHOP)))
updateEpSquare();
break;
}
// Update the key with the final value
st->key = k;
if (tt)
prefetch(tt->first_entry(key()));
// Calculate the repetition info. It is the ply distance from the previous
// occurrence of the same position, negative in the 3-fold case, or zero
// if the position was not repeated.