From e1dd005583bd6c2aaf58468efc5de86a3936380a Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Wed, 7 Jun 2023 09:01:05 +0200 Subject: [PATCH] Reintroduce SEE verification against discovered attacks Reintroduces https://github.com/official-stockfish/Stockfish/pull/4453 along with https://github.com/official-stockfish/Stockfish/pull/4469 Leaving out https://github.com/official-stockfish/Stockfish/pull/4533 https://github.com/official-stockfish/Stockfish/pull/4572 Passed STC: https://tests.stockfishchess.org/tests/view/647d8c37726f6b400e408a0a LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 143168 W: 38346 L: 37892 D: 66930 Ptnml(0-2): 352, 15672, 39164, 15962, 434 Passed LTC: https://tests.stockfishchess.org/tests/view/647ee8c528c4431bcb58e432 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 71538 W: 19560 L: 19190 D: 32788 Ptnml(0-2): 49, 6905, 21499, 7259, 57 closes https://github.com/official-stockfish/Stockfish/pull/4609 bench: 2595430 --- src/position.cpp | 19 ++++++++++++------- src/position.h | 1 + src/search.cpp | 23 +++++++++++++++++++++-- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/position.cpp b/src/position.cpp index af274d3f..2a9d798f 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1061,7 +1061,7 @@ Key Position::key_after(Move m) const { /// SEE value of move is greater or equal to the given threshold. We'll use an /// algorithm similar to alpha-beta pruning with a null window. -bool Position::see_ge(Move m, Value threshold) const { +bool Position::see_ge(Move m, Bitboard& occupied, Value threshold) const { assert(is_ok(m)); @@ -1080,7 +1080,7 @@ bool Position::see_ge(Move m, Value threshold) const { return true; assert(color_of(piece_on(from)) == sideToMove); - Bitboard occupied = pieces() ^ from ^ to; // xoring to is important for pinned piece logic + occupied = pieces() ^ from ^ to; // xoring to is important for pinned piece logic Color stm = sideToMove; Bitboard attackers = attackers_to(to, occupied); Bitboard stmAttackers, bb; @@ -1111,43 +1111,43 @@ bool Position::see_ge(Move m, Value threshold) const { // the bitboard 'attackers' any X-ray attackers behind it. if ((bb = stmAttackers & pieces(PAWN))) { + occupied ^= least_significant_square_bb(bb); if ((swap = PawnValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } else if ((bb = stmAttackers & pieces(KNIGHT))) { + occupied ^= least_significant_square_bb(bb); if ((swap = KnightValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); } else if ((bb = stmAttackers & pieces(BISHOP))) { + occupied ^= least_significant_square_bb(bb); if ((swap = BishopValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } else if ((bb = stmAttackers & pieces(ROOK))) { + occupied ^= least_significant_square_bb(bb); if ((swap = RookValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(ROOK, QUEEN); } else if ((bb = stmAttackers & pieces(QUEEN))) { + occupied ^= least_significant_square_bb(bb); if ((swap = QueenValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= (attacks_bb(to, occupied) & pieces(BISHOP, QUEEN)) | (attacks_bb(to, occupied) & pieces(ROOK , QUEEN)); @@ -1162,6 +1162,11 @@ bool Position::see_ge(Move m, Value threshold) const { return bool(res); } +bool Position::see_ge(Move m, Value threshold) const { + Bitboard occupied; + return see_ge(m, occupied, threshold); +} + /// Position::is_draw() tests whether the position is drawn by 50-move rule /// or by repetition. It does not detect stalemates. diff --git a/src/position.h b/src/position.h index 780d463c..2e6014db 100644 --- a/src/position.h +++ b/src/position.h @@ -144,6 +144,7 @@ public: // Static Exchange Evaluation bool see_ge(Move m, Value threshold = VALUE_ZERO) const; + bool see_ge(Move m, Bitboard& occupied, Value threshold = VALUE_ZERO) const; // Accessing hash keys Key key() const; diff --git a/src/search.cpp b/src/search.cpp index 593fdc72..b2c2344a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -990,9 +990,28 @@ moves_loop: // When in check, search starts here + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 7 < alpha) continue; + Bitboard occupied; // SEE based pruning (~11 Elo) - if (!pos.see_ge(move, Value(-205) * depth)) - continue; + if (!pos.see_ge(move, occupied, Value(-205) * depth)) + { + if (depth < 2 - capture) + continue; + // Don't prune the move if opponent Queen/Rook is under discovered attack after the exchanges + // Don't prune the move if opponent King is under discovered attack after or during the exchanges + Bitboard leftEnemies = (pos.pieces(~us, KING, QUEEN, ROOK)) & occupied; + Bitboard attacks = 0; + occupied |= to_sq(move); + while (leftEnemies && !attacks) + { + Square sq = pop_lsb(leftEnemies); + attacks |= pos.attackers_to(sq, occupied) & pos.pieces(us) & occupied; + // don't consider pieces which were already threatened/hanging before SEE exchanges + if (attacks && (sq != pos.square(~us) && (pos.attackers_to(sq, pos.pieces()) & pos.pieces(us)))) + attacks = 0; + } + if (!attacks) + continue; + } } else { -- 2.39.2