diff --git a/AUTHORS b/AUTHORS index 1c3f4b97f..62655dfde 100644 --- a/AUTHORS +++ b/AUTHORS @@ -205,6 +205,7 @@ Patrick Jansen (mibere) Patrick Leonhardt (Yoshie2000) Peter Schneider (pschneider1968) Peter Zsifkovits (CoffeeOne) +Pieter te Brake (pieterteb) PikaCat Praveen Kumar Tummala (praveentml) Prokop Randáček (ProkopRandacek) diff --git a/src/position.cpp b/src/position.cpp index a8d3cc506..f1222a66f 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -273,19 +273,19 @@ Position& Position::set(const string& fenStr, bool isChess960, StateInfo* si) { Bitboard pawns = attacks_bb(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(sideToMove), occ ^ pop_lsb(pawns)) & pieces(~sideToMove) & ~target); + legalEP |= !(attackers_to(square(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(epSquare, us) & pieces(them, PAWN); + + // If there are no pawns attacking the ep square, ep is not possible. + if (pawns) + { + Square ksq = square(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(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(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(them)); - } - - Square ksq = square(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(ksq, occupied) & pieces(us, QUEEN, ROOK)) - && !(attacks_bb(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.