]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Don't IID when in check also in PvNodes
[stockfish] / src / search.cpp
index 15981755b432fd3329760ba6af7b01065b5fd33f..af01050212ceca3ef4c9a4225c4952ede31b683b 100644 (file)
@@ -296,9 +296,12 @@ namespace {
     Value bestValue, alpha, beta, delta;
 
     memset(ss-1, 0, 4 * sizeof(Stack));
-    depth = BestMoveChanges = 0;
-    bestValue = delta = -VALUE_INFINITE;
     (ss-1)->currentMove = MOVE_NULL; // Hack to skip update gains
+
+    depth = BestMoveChanges = 0;
+    bestValue = delta = alpha = -VALUE_INFINITE;
+    beta = VALUE_INFINITE;
+
     TT.new_search();
     History.clear();
     Gains.clear();
@@ -328,17 +331,12 @@ namespace {
         // MultiPV loop. We perform a full root search for each PV line
         for (PVIdx = 0; PVIdx < PVSize; PVIdx++)
         {
-            // Set aspiration window default width
-            if (depth >= 5 && abs(RootMoves[PVIdx].prevScore) < VALUE_KNOWN_WIN)
+            // Reset aspiration window starting size
+            if (depth >= 5)
             {
                 delta = Value(16);
-                alpha = RootMoves[PVIdx].prevScore - delta;
-                beta  = RootMoves[PVIdx].prevScore + delta;
-            }
-            else
-            {
-                alpha = -VALUE_INFINITE;
-                beta  =  VALUE_INFINITE;
+                alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE);
+                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
             }
 
             // Start with a small aspiration window and, in case of fail high/low,
@@ -366,35 +364,28 @@ namespace {
                 if (Signals.stop)
                     return;
 
-                // In case of failing high/low increase aspiration window and
+                // In case of failing low/high increase aspiration window and
                 // research, otherwise exit the loop.
-                if (bestValue > alpha && bestValue < beta)
-                    break;
-
-                // Give some update (without cluttering the UI) before to research
-                if (Time::now() - SearchTime > 3000)
-                    sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
-
-                if (abs(bestValue) >= VALUE_KNOWN_WIN)
+                if (bestValue <= alpha)
                 {
-                    alpha = -VALUE_INFINITE;
-                    beta  =  VALUE_INFINITE;
+                    alpha = std::max(bestValue - delta, -VALUE_INFINITE);
+
+                    Signals.failedLowAtRoot = true;
+                    Signals.stopOnPonderhit = false;
                 }
                 else if (bestValue >= beta)
-                {
-                    beta += delta;
-                    delta += delta / 2;
-                }
+                    beta = std::min(bestValue + delta, VALUE_INFINITE);
+
                 else
-                {
-                    Signals.failedLowAtRoot = true;
-                    Signals.stopOnPonderhit = false;
+                    break;
 
-                    alpha -= delta;
-                    delta += delta / 2;
-                }
+                delta += delta / 2;
 
                 assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
+
+                // Give some update (without cluttering the UI) before to research
+                if (Time::now() - SearchTime > 3000)
+                    sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
             }
 
             // Sort the PV lines searched so far and update the GUI
@@ -491,7 +482,7 @@ namespace {
     assert(PvNode || (alpha == beta - 1));
     assert(depth > DEPTH_ZERO);
 
-    Move movesSearched[64];
+    Move quietsSearched[64];
     StateInfo st;
     const TTEntry *tte;
     SplitPoint* splitPoint;
@@ -502,11 +493,11 @@ namespace {
     Value eval, nullValue, futilityValue;
     bool inCheck, givesCheck, pvMove, singularExtensionNode;
     bool captureOrPromotion, dangerous, doFullDepthSearch;
-    int moveCount, playedMoveCount;
+    int moveCount, quietCount;
 
     // Step 1. Initialize node
     Thread* thisThread = pos.this_thread();
-    moveCount = playedMoveCount = 0;
+    moveCount = quietCount = 0;
     inCheck = pos.checkers();
 
     if (SpNode)
@@ -521,7 +512,7 @@ namespace {
 
         assert(splitPoint->bestValue > -VALUE_INFINITE && splitPoint->moveCount > 0);
 
-        goto split_point_start;
+        goto moves_loop;
     }
 
     bestValue = -VALUE_INFINITE;
@@ -590,7 +581,10 @@ namespace {
 
     // Step 5. Evaluate the position statically and update parent's gain statistics
     if (inCheck)
+    {
         ss->staticEval = ss->evalMargin = eval = VALUE_NONE;
+        goto moves_loop;
+    }
 
     else if (tte)
     {
@@ -614,10 +608,10 @@ namespace {
 
     // Update gain for the parent non-capture move given the static position
     // evaluation before and after the move.
-    if (   (move = (ss-1)->currentMove) != MOVE_NULL
-        && (ss-1)->staticEval != VALUE_NONE
+    if (   !pos.captured_piece_type()
         &&  ss->staticEval != VALUE_NONE
-        && !pos.captured_piece_type()
+        && (ss-1)->staticEval != VALUE_NONE
+        && (move = (ss-1)->currentMove) != MOVE_NULL
         &&  type_of(move) == NORMAL)
     {
         Square to = to_sq(move);
@@ -627,7 +621,6 @@ namespace {
     // Step 6. Razoring (is omitted in PV nodes)
     if (   !PvNode
         &&  depth < 4 * ONE_PLY
-        && !inCheck
         &&  eval + razor_margin(depth) < beta
         &&  ttMove == MOVE_NONE
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
@@ -647,7 +640,6 @@ namespace {
     if (   !PvNode
         && !ss->skipNullMove
         &&  depth < 4 * ONE_PLY
-        && !inCheck
         &&  eval - futility_margin(depth, (ss-1)->futilityMoveCount) >= beta
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
         &&  abs(eval) < VALUE_KNOWN_WIN
@@ -658,7 +650,6 @@ namespace {
     if (   !PvNode
         && !ss->skipNullMove
         &&  depth > ONE_PLY
-        && !inCheck
         &&  eval >= beta
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
         &&  pos.non_pawn_material(pos.side_to_move()))
@@ -720,7 +711,6 @@ namespace {
     // prune the previous move.
     if (   !PvNode
         &&  depth >= 5 * ONE_PLY
-        && !inCheck
         && !ss->skipNullMove
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY)
     {
@@ -749,7 +739,7 @@ namespace {
     // Step 10. Internal iterative deepening
     if (   depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY)
         && ttMove == MOVE_NONE
-        && (PvNode || (!inCheck && ss->staticEval + Value(256) >= beta)))
+        && (PvNode || ss->staticEval + Value(256) >= beta))
     {
         Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4);
 
@@ -761,7 +751,7 @@ namespace {
         ttMove = tte ? tte->move() : MOVE_NONE;
     }
 
-split_point_start: // At split points actual search starts from here
+moves_loop: // When in check and at SpNode search starts from here
 
     Square prevMoveSq = to_sq((ss-1)->currentMove);
     Move countermoves[] = { Countermoves[pos.piece_on(prevMoveSq)][prevMoveSq].first,
@@ -820,12 +810,7 @@ split_point_start: // At split points actual search starts from here
       givesCheck = pos.move_gives_check(move, ci);
       dangerous =   givesCheck
                  || pos.is_passed_pawn_push(move)
-                 || type_of(move) == CASTLE
-                 || (   captureOrPromotion // Entering a pawn endgame?
-                     && type_of(pos.piece_on(to_sq(move))) != PAWN
-                     && type_of(move) == NORMAL
-                     && (  pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
-                         - PieceValue[MG][pos.piece_on(to_sq(move))] == VALUE_ZERO));
+                 || type_of(move) == CASTLE;
 
       // Step 12. Extend checks and, in PV nodes, also dangerous moves
       if (PvNode && dangerous)
@@ -926,8 +911,8 @@ split_point_start: // At split points actual search starts from here
 
       pvMove = PvNode && moveCount == 1;
       ss->currentMove = move;
-      if (!SpNode && !captureOrPromotion && playedMoveCount < 64)
-          movesSearched[playedMoveCount++] = move;
+      if (!SpNode && !captureOrPromotion && quietCount < 64)
+          quietsSearched[quietCount++] = move;
 
       // Step 14. Make the move
       pos.do_move(move, st, ci, givesCheck);
@@ -1078,43 +1063,37 @@ split_point_start: // At split points actual search starts from here
 
     // If we have pruned all the moves without searching return a fail-low score
     if (bestValue == -VALUE_INFINITE)
-    {
-        assert(!playedMoveCount);
-
         bestValue = alpha;
-    }
 
-    if (bestValue >= beta) // Failed high
+    TT.store(posKey, value_to_tt(bestValue, ss->ply),
+             bestValue >= beta  ? BOUND_LOWER :
+             PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
+             depth, bestMove, ss->staticEval, ss->evalMargin);
+
+    // Quiet best move: update killers, history and countermoves
+    if (    bestValue >= beta
+        && !pos.is_capture_or_promotion(bestMove)
+        && !inCheck)
     {
-        TT.store(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, depth,
-                 bestMove, ss->staticEval, ss->evalMargin);
-
-        if (!pos.is_capture_or_promotion(bestMove) && !inCheck)
+        if (ss->killers[0] != bestMove)
         {
-            if (bestMove != ss->killers[0])
-            {
-                ss->killers[1] = ss->killers[0];
-                ss->killers[0] = bestMove;
-            }
-
-            // Increase history value of the cut-off move
-            Value bonus = Value(int(depth) * int(depth));
-            History.update(pos.piece_moved(bestMove), to_sq(bestMove), bonus);
-            if (is_ok((ss-1)->currentMove))
-                Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, bestMove);
+            ss->killers[1] = ss->killers[0];
+            ss->killers[0] = bestMove;
+        }
 
-            // Decrease history of all the other played non-capture moves
-            for (int i = 0; i < playedMoveCount - 1; i++)
-            {
-                Move m = movesSearched[i];
-                History.update(pos.piece_moved(m), to_sq(m), -bonus);
-            }
+        // Increase history value of the cut-off move and decrease all the other
+        // played non-capture moves.
+        Value bonus = Value(int(depth) * int(depth));
+        History.update(pos.piece_moved(bestMove), to_sq(bestMove), bonus);
+        for (int i = 0; i < quietCount - 1; i++)
+        {
+            Move m = quietsSearched[i];
+            History.update(pos.piece_moved(m), to_sq(m), -bonus);
         }
+
+        if (is_ok((ss-1)->currentMove))
+            Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, bestMove);
     }
-    else // Failed low or PV search
-        TT.store(posKey, value_to_tt(bestValue, ss->ply),
-                 PvNode && bestMove != MOVE_NONE ? BOUND_EXACT : BOUND_UPPER,
-                 depth, bestMove, ss->staticEval, ss->evalMargin);
 
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
@@ -1162,8 +1141,7 @@ split_point_start: // At split points actual search starts from here
     ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
                                                   : DEPTH_QS_NO_CHECKS;
 
-    // Transposition table lookup. At PV nodes, we don't use the TT for
-    // pruning, but only for move ordering.
+    // Transposition table lookup
     posKey = pos.key();
     tte = TT.probe(posKey);
     ttMove = tte ? tte->move() : MOVE_NONE;