]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Don't check for early stop when StopOnPonderhit is set
[stockfish] / src / search.cpp
index fc5dc4ee8ab305759e255a7d86ed110795decbf2..061ba5eea95eaaa5607f33f3f6e4c0ac42715bf5 100644 (file)
@@ -150,7 +150,7 @@ namespace {
 
   // Easy move margin. An easy move candidate must be at least this much
   // better than the second best move.
-  const Value EasyMoveMargin = Value(0x200);
+  const Value EasyMoveMargin = Value(0x150);
 
 
   /// Namespace variables
@@ -162,7 +162,7 @@ namespace {
   int MultiPV, UCIMultiPV, MultiPVIdx;
 
   // Time management variables
-  bool StopOnPonderhit, FirstRootMove, StopRequest, QuitRequest, AspirationFailLow;
+  volatile bool StopOnPonderhit, FirstRootMove, StopRequest, QuitRequest, AspirationFailLow;
   TimeManager TimeMgr;
   SearchLimits Limits;
 
@@ -465,9 +465,10 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
       pos.undo_move(bestMove); // Return from think() with unchanged position
   }
 
-  // If we are pondering or in infinite search, we shouldn't print the best move
+  // When we reach max depth we arrive here even without a StopRequest, but if
+  // we are pondering or in infinite search, we shouldn't print the best move
   // before we are told to do so.
-  if (Limits.ponder || Limits.infinite)
+  if (!StopRequest && (Limits.ponder || Limits.infinite))
       wait_for_stop_or_ponderhit();
 
   // Could be MOVE_NONE when searching on a stalemate position
@@ -497,13 +498,14 @@ namespace {
     int bestMoveChanges[PLY_MAX_PLUS_2];
     int depth, aspirationDelta;
     Value bestValue, alpha, beta;
-    Move bestMove, easyMove, skillBest, skillPonder;
+    Move bestMove, skillBest, skillPonder;
+    bool bestMoveNeverChanged = true;
 
     // Initialize stuff before a new search
     memset(ss, 0, 4 * sizeof(SearchStack));
     TT.new_search();
     H.clear();
-    *ponderMove = bestMove = easyMove = skillBest = skillPonder = MOVE_NONE;
+    *ponderMove = bestMove = skillBest = skillPonder = MOVE_NONE;
     depth = aspirationDelta = 0;
     bestValue = alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
     ss->currentMove = MOVE_NULL; // Hack to skip update gains
@@ -643,27 +645,13 @@ namespace {
             log << pretty_pv(pos, depth, bestValue, elapsed_search_time(), &Rml[0].pv[0]) << endl;
         }
 
-        // Init easyMove at first iteration or drop it if differs from the best move
-        if (depth == 1 && (Rml.size() == 1 || Rml[0].score > Rml[1].score + EasyMoveMargin))
-            easyMove = bestMove;
-        else if (bestMove != easyMove)
-            easyMove = MOVE_NONE;
+        // Filter out startup noise when monitoring best move stability
+        if (depth > 2 && bestMoveChanges[depth])
+            bestMoveNeverChanged = false;
 
-        // Check for some early stop condition
-        if (!StopRequest && Limits.useTimeManagement())
+        // Do we have time for the next iteration? Can we stop searching now?
+        if (!StopRequest && !StopOnPonderhit && Limits.useTimeManagement())
         {
-            // Easy move: Stop search early if one move seems to be much better
-            // than the others or if there is only a single legal move. Also in
-            // the latter case search to some depth anyway to get a proper score.
-            if (   depth >= 7
-                && easyMove == bestMove
-                && (   Rml.size() == 1
-                    ||(   Rml[0].nodes > (pos.nodes_searched() * 85) / 100
-                       && elapsed_search_time() > TimeMgr.available_time() / 16)
-                    ||(   Rml[0].nodes > (pos.nodes_searched() * 98) / 100
-                       && elapsed_search_time() > TimeMgr.available_time() / 32)))
-                StopRequest = true;
-
             // Take in account some extra time if the best move has changed
             if (depth > 4 && depth < 50)
                 TimeMgr.pv_instability(bestMoveChanges[depth], bestMoveChanges[depth - 1]);
@@ -673,8 +661,25 @@ namespace {
             if (elapsed_search_time() > (TimeMgr.available_time() * 62) / 100)
                 StopRequest = true;
 
+            // Stop search early if one move seems to be much better than others
+            if (   depth >= 10
+                && !StopRequest
+                && (   bestMoveNeverChanged
+                    || elapsed_search_time() > (TimeMgr.available_time() * 40) / 100))
+            {
+                Value rBeta = bestValue - EasyMoveMargin;
+                (ss+1)->excludedMove = bestMove;
+                (ss+1)->skipNullMove = true;
+                Value v = search<NonPV>(pos, ss+1, rBeta - 1, rBeta, (depth * ONE_PLY) / 2);
+                (ss+1)->skipNullMove = false;
+                (ss+1)->excludedMove = MOVE_NONE;
+
+                if (v < rBeta)
+                    StopRequest = true;
+            }
+
             // If we are allowed to ponder do not stop the search now but keep pondering
-            if (StopRequest && Limits.ponder)
+            if (StopRequest && Limits.ponder) // FIXME Limits.ponder is racy
             {
                 StopRequest = false;
                 StopOnPonderhit = true;
@@ -1027,8 +1032,7 @@ split_point_start: // At split points actual search starts from here
                    << " currmovenumber " << moveCount + MultiPVIdx << endl;
       }
 
-      // At Root and at first iteration do a PV search on all the moves to score root moves
-      isPvMove = (PvNode && moveCount <= (RootNode && depth <= ONE_PLY ? MAX_MOVES : 1));
+      isPvMove = (PvNode && moveCount <= 1);
       givesCheck = pos.move_gives_check(move, ci);
       captureOrPromotion = pos.is_capture_or_promotion(move);