]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Move time related global variables under TimeManager
[stockfish] / src / search.cpp
index 52be2e6435ac7e5642265d46327338a39d834feb..fa7052d0dc0c2605201a17bd283742541e1c3c59 100644 (file)
@@ -251,10 +251,10 @@ namespace {
   int MultiPV;
 
   // Time managment variables
-  int SearchStartTime, MaxNodes, MaxDepth, OptimumSearchTime;
-  int MaximumSearchTime, ExtraSearchTime, ExactMaxTime;
+  int SearchStartTime, MaxNodes, MaxDepth, ExactMaxTime;
   bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
   bool FirstRootMove, AbortSearch, Quit, AspirationFailLow;
+  TimeManager TimeMgr;
 
   // Log file
   bool UseLogFile;
@@ -401,7 +401,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int time[], int incr
 
   // Initialize global search variables
   StopOnPonderhit = AbortSearch = Quit = AspirationFailLow = false;
-  OptimumSearchTime = MaximumSearchTime = ExtraSearchTime = 0;
   NodesSincePoll = 0;
   TM.resetNodeCounters();
   SearchStartTime = get_system_time();
@@ -473,16 +472,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int time[], int incr
   int myTime = time[pos.side_to_move()];
   int myIncrement = increment[pos.side_to_move()];
   if (UseTimeManagement)
-  {
-      get_search_times(myTime, myIncrement, movesToGo, pos.startpos_ply_counter(),
-                       &OptimumSearchTime, &MaximumSearchTime);
-
-      if (get_option_value_bool("Ponder"))
-      {
-          OptimumSearchTime += OptimumSearchTime / 4;
-          OptimumSearchTime = Min(OptimumSearchTime, MaximumSearchTime);
-      }
-  }
+      TimeMgr.update(myTime, myIncrement, movesToGo, pos.startpos_ply_counter());
 
   // Set best NodesBetweenPolls interval to avoid lagging under
   // heavy time pressure.
@@ -626,20 +616,20 @@ namespace {
             if (   Iteration >= 8
                 && EasyMove == pv[0]
                 && (  (   rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100
-                       && current_search_time() > OptimumSearchTime / 16)
+                       && current_search_time() > TimeMgr.optimumSearchTime / 16)
                     ||(   rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100
-                       && current_search_time() > OptimumSearchTime / 32)))
+                       && current_search_time() > TimeMgr.optimumSearchTime / 32)))
                 stopSearch = true;
 
             // Add some extra time if the best move has changed during the last two iterations
             if (Iteration > 5 && Iteration <= 50)
-                ExtraSearchTime = BestMoveChangesByIteration[Iteration]   * (OptimumSearchTime / 2)
-                                + BestMoveChangesByIteration[Iteration-1] * (OptimumSearchTime / 3);
+                TimeMgr.best_move_changes(BestMoveChangesByIteration[Iteration],
+                                          BestMoveChangesByIteration[Iteration-1]);
 
             // Stop search if most of MaxSearchTime is consumed at the end of the
             // iteration. We probably don't have enough time to search the first
             // move at the next iteration anyway.
-            if (current_search_time() > ((OptimumSearchTime + ExtraSearchTime) * 80) / 128)
+            if (current_search_time() > (TimeMgr.available_time() * 80) / 128)
                 stopSearch = true;
 
             if (stopSearch)
@@ -1043,28 +1033,27 @@ namespace {
         return value_from_tt(tte->value(), ply);
     }
 
-    // Step 5. Evaluate the position statically
-    // At PV nodes we do this only to update gain statistics
+    // Step 5. Evaluate the position statically and
+    // update gain statistics of parent move.
     isCheck = pos.is_check();
-    if (!isCheck)
+    if (isCheck)
+        ss->eval = VALUE_NONE;
+    else if (tte)
     {
-        if (tte)
-        {
-            assert(tte->static_value() != VALUE_NONE);
+        assert(tte->static_value() != VALUE_NONE);
 
-            ss->eval = tte->static_value();
-            ei.kingDanger[pos.side_to_move()] = tte->king_danger();
-        }
-        else
-        {
-            ss->eval = evaluate(pos, ei);
-            TT.store(posKey, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]);
-        }
-        refinedValue = refine_eval(tte, ss->eval, ply); // Enhance accuracy with TT value if possible
-        update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
+        ss->eval = tte->static_value();
+        ei.kingDanger[pos.side_to_move()] = tte->king_danger();
+        refinedValue = refine_eval(tte, ss->eval, ply);
     }
     else
-        ss->eval = VALUE_NONE;
+    {
+        refinedValue = ss->eval = evaluate(pos, ei);
+        TT.store(posKey, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]);
+    }
+
+    // Save gain for the parent non-capture move
+    update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
 
     // Step 6. Razoring (is omitted in PV nodes)
     if (   !PvNode
@@ -1090,8 +1079,8 @@ namespace {
     if (   !PvNode
         && !ss->skipNullMove
         &&  depth < RazorDepth
-        &&  refinedValue >= beta + futility_margin(depth, 0)
         && !isCheck
+        &&  refinedValue >= beta + futility_margin(depth, 0)
         && !value_is_mate(beta)
         &&  pos.non_pawn_material(pos.side_to_move()))
         return refinedValue - futility_margin(depth, 0);
@@ -1103,8 +1092,8 @@ namespace {
     if (   !PvNode
         && !ss->skipNullMove
         &&  depth > OnePly
-        &&  refinedValue >= beta - (depth >= 4 * OnePly ? NullMoveMargin : 0)
         && !isCheck
+        &&  refinedValue >= beta - (depth >= 4 * OnePly ? NullMoveMargin : 0)
         && !value_is_mate(beta)
         &&  pos.non_pawn_material(pos.side_to_move()))
     {
@@ -1222,7 +1211,7 @@ namespace {
           // singular extension search result is still valid.
           if (  !PvNode
               && depth < SingularExtensionDepth[PvNode] + 5 * OnePly
-              && ((ttx = TT.retrieve(pos.get_exclusion_key())) != NULL))
+              && (ttx = TT.retrieve(pos.get_exclusion_key())) != NULL)
           {
               if (is_upper_bound(ttx->type()))
                   ext = OnePly;
@@ -1350,7 +1339,7 @@ namespace {
           bestValue = value;
           if (value > alpha)
           {
-              if (PvNode && value < beta) // This guarantees that always: alpha < beta
+              if (PvNode && value < beta) // We want always alpha < beta
                   alpha = value;
 
               if (value == value_mate_in(ply + 1))
@@ -1377,7 +1366,7 @@ namespace {
     // no legal moves, it must be mate or stalemate.
     // If one move was excluded return fail low score.
     if (!moveCount)
-        return excludedMove ? oldAlpha : (isCheck ? value_mated_in(ply) : VALUE_DRAW);
+        return excludedMove ? oldAlpha : isCheck ? value_mated_in(ply) : VALUE_DRAW;
 
     // Step 20. Update tables
     // If the search is not aborted, update the transposition table,
@@ -1385,9 +1374,9 @@ namespace {
     if (AbortSearch || TM.thread_should_stop(threadID))
         return bestValue;
 
-    ValueType f = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
+    ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
     move = (bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove);
-    TT.store(posKey, value_to_tt(bestValue, ply), f, depth, move, ss->eval, ei.kingDanger[pos.side_to_move()]);
+    TT.store(posKey, value_to_tt(bestValue, ply), vt, depth, move, ss->eval, ei.kingDanger[pos.side_to_move()]);
 
     // Update killers and history only for non capture moves that fails high
     if (bestValue >= beta)
@@ -1460,6 +1449,7 @@ namespace {
         if (tte)
         {
             assert(tte->static_value() != VALUE_NONE);
+
             ei.kingDanger[pos.side_to_move()] = tte->king_danger();
             bestValue = tte->static_value();
         }
@@ -1569,8 +1559,8 @@ namespace {
 
     // Update transposition table
     Depth d = (depth == Depth(0) ? Depth(0) : Depth(-1));
-    ValueType f = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
-    TT.store(pos.get_key(), value_to_tt(bestValue, ply), f, d, ss->bestMove, ss->eval, ei.kingDanger[pos.side_to_move()]);
+    ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
+    TT.store(pos.get_key(), value_to_tt(bestValue, ply), vt, d, ss->bestMove, ss->eval, ei.kingDanger[pos.side_to_move()]);
 
     // Update killers only for checking moves that fails high
     if (    bestValue >= beta
@@ -1989,8 +1979,7 @@ namespace {
 
   Value refine_eval(const TTEntry* tte, Value defaultEval, int ply) {
 
-      if (!tte)
-          return defaultEval;
+      assert(tte);
 
       Value v = value_from_tt(tte->value(), ply);
 
@@ -2046,8 +2035,7 @@ namespace {
         && before != VALUE_NONE
         && after != VALUE_NONE
         && pos.captured_piece() == NO_PIECE_TYPE
-        && !move_is_castle(m)
-        && !move_is_promotion(m))
+        && !move_is_special(m))
         H.set_gain(pos.piece_on(move_to(m)), move_to(m), -(before + after));
   }
 
@@ -2147,9 +2135,9 @@ namespace {
 
     bool stillAtFirstMove =    FirstRootMove
                            && !AspirationFailLow
-                           &&  t > OptimumSearchTime + ExtraSearchTime;
+                           &&  t > TimeMgr.available_time();
 
-    bool noMoreTime =   t > MaximumSearchTime
+    bool noMoreTime =   t > TimeMgr.maximumSearchTime
                      || stillAtFirstMove;
 
     if (   (Iteration >= 3 && UseTimeManagement && noMoreTime)
@@ -2170,9 +2158,9 @@ namespace {
 
     bool stillAtFirstMove =    FirstRootMove
                            && !AspirationFailLow
-                           &&  t > OptimumSearchTime + ExtraSearchTime;
+                           &&  t > TimeMgr.available_time();
 
-    bool noMoreTime =   t > MaximumSearchTime
+    bool noMoreTime =   t > TimeMgr.maximumSearchTime
                      || stillAtFirstMove;
 
     if (Iteration >= 3 && UseTimeManagement && (noMoreTime || StopOnPonderhit))