]> git.sesse.net Git - stockfish/commitdiff
Reintroduce SEE verification against discovered attacks
authorGuenther Demetz <guenther.demetz@wuerth-phoenix.com>
Wed, 7 Jun 2023 07:01:05 +0000 (09:01 +0200)
committerStéphane Nicolet <Stephane.Nicolet@u-paris2.fr>
Sun, 11 Jun 2023 13:13:57 +0000 (15:13 +0200)
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
src/position.h
src/search.cpp

index af274d3f2c64183e61eaa163a121112082b8ede1..2a9d798ff7d0d85afa60c75f35646b7e4b399ef6 100644 (file)
@@ -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<BISHOP>(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<BISHOP>(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<ROOK>(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<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
                       | (attacks_bb<ROOK  >(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.
index 780d463cc6475060755843f88570f00221802079..2e6014dbe6ebb3170d8275c6da11083d4086c0db 100644 (file)
@@ -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;
index 593fdc722e0b13a2a1c3d3b8c6087e9b5e613612..b2c2344ac0aaff10a249bfb7f64a22fa0e648d6f 100644 (file)
@@ -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<KING>(~us) && (pos.attackers_to(sq, pos.pieces()) & pos.pieces(us))))
+                         attacks = 0;
+                 }
+                 if (!attacks)
+                    continue;
+              }
           }
           else
           {