]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Extra time management safety
[stockfish] / src / search.cpp
index 189e11d0fe9991231393ebece1d657774f0520b1..3ed8ced0326e5ab162f3f70559a1bc80c8a07358 100644 (file)
@@ -139,6 +139,9 @@ namespace {
   // better than the second best move.
   const Value EasyMoveMargin = Value(0x150);
 
+  // This is the minimum interval in msec between two check_time() calls
+  const int TimerResolution = 5;
+
 
   /// Namespace variables
 
@@ -197,19 +200,19 @@ namespace {
   FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) {
 
     // Test for a pawn pushed to 7th or a passed pawn move
-    if (type_of(pos.piece_on(move_from(m))) == PAWN)
+    if (type_of(pos.piece_on(from_sq(m))) == PAWN)
     {
         Color c = pos.side_to_move();
-        if (   relative_rank(c, move_to(m)) == RANK_7
-            || pos.pawn_is_passed(c, move_to(m)))
+        if (   relative_rank(c, to_sq(m)) == RANK_7
+            || pos.pawn_is_passed(c, to_sq(m)))
             return true;
     }
 
     // Test for a capture that triggers a pawn endgame
     if (   captureOrPromotion
-        && type_of(pos.piece_on(move_to(m))) != PAWN
+        && type_of(pos.piece_on(to_sq(m))) != PAWN
         && (  pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
-            - PieceValueMidgame[pos.piece_on(move_to(m))] == VALUE_ZERO)
+            - PieceValueMidgame[pos.piece_on(to_sq(m))] == VALUE_ZERO)
         && !is_special(m))
         return true;
 
@@ -290,22 +293,17 @@ void Search::think() {
   // Populate RootMoves with all the legal moves (default) or, if a SearchMoves
   // is given, with the subset of legal moves to search.
   for (MoveList<MV_LEGAL> ml(pos); !ml.end(); ++ml)
-      if (   SearchMoves.empty()
-          || count(SearchMoves.begin(), SearchMoves.end(), ml.move()))
+      if (SearchMoves.empty() || count(SearchMoves.begin(), SearchMoves.end(), ml.move()))
           RootMoves.push_back(RootMove(ml.move()));
 
   if (Options["OwnBook"])
   {
-      if (book.name() != (string)Options["Book File"])
-          book.open(Options["Book File"]);
-
-      Move bookMove = book.probe(pos, Options["Best Book Move"]);
+      Move bookMove = book.probe(pos, Options["Book File"], Options["Best Book Move"]);
 
-      if (   bookMove != MOVE_NONE
-          && count(RootMoves.begin(), RootMoves.end(), bookMove))
+      if (bookMove && count(RootMoves.begin(), RootMoves.end(), bookMove))
       {
           std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), bookMove));
-          goto finish;
+          goto finalize;
       }
   }
 
@@ -348,8 +346,8 @@ void Search::think() {
 
   // Set best timer interval to avoid lagging under time pressure. Timer is
   // used to check for remaining available thinking time.
-  if (TimeMgr.available_time())
-      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 8, 20)));
+  if (Limits.use_time_management())
+      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 16, TimerResolution)));
   else
       Threads.set_timer(100);
 
@@ -375,7 +373,7 @@ void Search::think() {
       pos.undo_move(RootMoves[0].pv[0]);
   }
 
-finish:
+finalize:
 
   // 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
@@ -518,7 +516,7 @@ namespace {
             bestMoveNeverChanged = false;
 
         // Do we have time for the next iteration? Can we stop searching now?
-        if (!Signals.stop && !Signals.stopOnPonderhit && Limits.useTimeManagement())
+        if (!Signals.stop && !Signals.stopOnPonderhit && Limits.use_time_management())
         {
             bool stop = false; // Local variable, not the volatile Signals.stop
 
@@ -706,7 +704,7 @@ namespace {
         && pos.captured_piece_type() == NO_PIECE_TYPE
         && !is_special(move))
     {
-        Square to = move_to(move);
+        Square to = to_sq(move);
         H.update_gain(pos.piece_on(to), to, -(ss-1)->eval - ss->eval);
     }
 
@@ -870,7 +868,8 @@ split_point_start: // At split points actual search starts from here
     // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
     while (   bestValue < beta
            && (move = mp.next_move()) != MOVE_NONE
-           && !thread.cutoff_occurred())
+           && !thread.cutoff_occurred()
+           && !Signals.stop)
     {
       assert(is_ok(move));
 
@@ -971,7 +970,7 @@ split_point_start: // At split points actual search starts from here
           // but fixing this made program slightly weaker.
           Depth predictedDepth = newDepth - reduction<PvNode>(depth, moveCount);
           futilityValue =  futilityBase + futility_margin(predictedDepth, moveCount)
-                         + H.gain(pos.piece_on(move_from(move)), move_to(move));
+                         + H.gain(pos.piece_on(from_sq(move)), to_sq(move));
 
           if (futilityValue < beta)
           {
@@ -1155,13 +1154,13 @@ split_point_start: // At split points actual search starts from here
 
             // Increase history value of the cut-off move
             Value bonus = Value(int(depth) * int(depth));
-            H.add(pos.piece_on(move_from(move)), move_to(move), bonus);
+            H.add(pos.piece_on(from_sq(move)), to_sq(move), bonus);
 
             // Decrease history of all the other played non-capture moves
             for (int i = 0; i < playedMoveCount - 1; i++)
             {
                 Move m = movesSearched[i];
-                H.add(pos.piece_on(move_from(m)), move_to(m), -bonus);
+                H.add(pos.piece_on(from_sq(m)), to_sq(m), -bonus);
             }
         }
     }
@@ -1267,7 +1266,7 @@ split_point_start: // At split points actual search starts from here
     // to search the moves. Because the depth is <= 0 here, only captures,
     // queen promotions and checks (only if depth >= DEPTH_QS_CHECKS) will
     // be generated.
-    MovePicker mp(pos, ttMove, depth, H, move_to((ss-1)->currentMove));
+    MovePicker mp(pos, ttMove, depth, H, to_sq((ss-1)->currentMove));
     CheckInfo ci(pos);
 
     // Loop through the moves until no moves remain or a beta cutoff occurs
@@ -1288,7 +1287,7 @@ split_point_start: // At split points actual search starts from here
           && !pos.is_passed_pawn_push(move))
       {
           futilityValue =  futilityBase
-                         + PieceValueEndgame[pos.piece_on(move_to(move))]
+                         + PieceValueEndgame[pos.piece_on(to_sq(move))]
                          + (is_enpassant(move) ? PawnValueEndgame : VALUE_ZERO);
 
           if (futilityValue < beta)
@@ -1392,8 +1391,8 @@ split_point_start: // At split points actual search starts from here
     Color them;
     Value futilityValue, bv = *bestValue;
 
-    from = move_from(move);
-    to = move_to(move);
+    from = from_sq(move);
+    to = to_sq(move);
     them = flip(pos.side_to_move());
     ksq = pos.king_square(them);
     kingAtt = pos.attacks_from<KING>(ksq);
@@ -1453,14 +1452,14 @@ split_point_start: // At split points actual search starts from here
     assert(is_ok(m2));
 
     // Case 1: The moving piece is the same in both moves
-    f2 = move_from(m2);
-    t1 = move_to(m1);
+    f2 = from_sq(m2);
+    t1 = to_sq(m1);
     if (f2 == t1)
         return true;
 
     // Case 2: The destination square for m2 was vacated by m1
-    t2 = move_to(m2);
-    f1 = move_from(m1);
+    t2 = to_sq(m2);
+    f1 = from_sq(m1);
     if (t2 == f1)
         return true;
 
@@ -1533,10 +1532,10 @@ split_point_start: // At split points actual search starts from here
 
     Square mfrom, mto, tfrom, tto;
 
-    mfrom = move_from(m);
-    mto = move_to(m);
-    tfrom = move_from(threat);
-    tto = move_to(threat);
+    mfrom = from_sq(m);
+    mto = to_sq(m);
+    tfrom = from_sq(threat);
+    tto = to_sq(threat);
 
     // Case 1: Don't prune moves which move the threatened piece
     if (mfrom == tto)
@@ -1962,11 +1961,11 @@ void Thread::idle_loop(SplitPoint* sp) {
 }
 
 
-/// do_timer_event() is called by the timer thread when the timer triggers. It
-/// is used to print debug info and, more important, to detect when we are out of
+/// check_time() is called by the timer thread when the timer triggers. It is
+/// used to print debug info and, more important, to detect when we are out of
 /// available time and so stop the search.
 
-void do_timer_event() {
+void check_time() {
 
   static int lastInfoTime;
   int e = elapsed_time();
@@ -1984,10 +1983,10 @@ void do_timer_event() {
                          && !Signals.failedLowAtRoot
                          &&  e > TimeMgr.available_time();
 
-  bool noMoreTime =   e > TimeMgr.maximum_time()
+  bool noMoreTime =   e > TimeMgr.maximum_time() - 2 * TimerResolution
                    || stillAtFirstMove;
 
-  if (   (Limits.useTimeManagement() && noMoreTime)
+  if (   (Limits.use_time_management() && noMoreTime)
       || (Limits.maxTime && e >= Limits.maxTime)
          /* missing nodes limit */ ) // FIXME
       Signals.stop = true;