]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Retire easy move
[stockfish] / src / search.cpp
index c883a125c245a3ebc0d1cbdaafcc8d676753042e..be82568a2179f03eb9bce512617950a7abad8f50 100644 (file)
@@ -43,7 +43,7 @@ namespace Search {
   std::vector<RootMove> RootMoves;
   Position RootPos;
   Color RootColor;
-  Time::point SearchTime;
+  Time::point SearchTime, IterationTime;
   StateStackPtr SetupStates;
 }
 
@@ -94,6 +94,7 @@ namespace {
   void id_loop(Position& pos);
   Value value_to_tt(Value v, int ply);
   Value value_from_tt(Value v, int ply);
+  void update_stats(Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt);
   string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
 
   struct Skill {
@@ -395,6 +396,8 @@ namespace {
                 sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
         }
 
+        IterationTime = Time::now() - SearchTime;
+
         // If skill levels are enabled and time is up, pick a sub-optimal best move
         if (skill.enabled() && skill.time_to_pick(depth))
             skill.pick_move();
@@ -425,32 +428,13 @@ namespace {
             if (depth > 4 && depth < 50 &&  PVSize == 1)
                 TimeMgr.pv_instability(BestMoveChanges);
 
-            // Stop the search if most of the available time has been used. We
-            // probably don't have enough time to search the first move at the
-            // next iteration anyway.
-            if (Time::now() - SearchTime > (TimeMgr.available_time() * 62) / 100)
+            // Stop the search if only one legal move is available or most
+            // of the available time has been used. We probably don't have
+            // enough time to search the first move at the next iteration anyway.
+            if (   RootMoves.size() == 1
+                || IterationTime > (TimeMgr.available_time() * 62) / 100)
                 stop = true;
 
-            // Stop the search early if one move seems to be much better than others
-            if (    depth >= 12
-                &&  BestMoveChanges <= DBL_EPSILON
-                && !stop
-                &&  PVSize == 1
-                &&  bestValue > VALUE_MATED_IN_MAX_PLY
-                && (   RootMoves.size() == 1
-                    || Time::now() - SearchTime > (TimeMgr.available_time() * 20) / 100))
-            {
-                Value rBeta = bestValue - 2 * PawnValueMg;
-                ss->excludedMove = RootMoves[0].pv[0];
-                ss->skipNullMove = true;
-                Value v = search<NonPV>(pos, ss, rBeta - 1, rBeta, (depth - 3) * ONE_PLY, true);
-                ss->skipNullMove = false;
-                ss->excludedMove = MOVE_NONE;
-
-                if (v < rBeta)
-                    stop = true;
-            }
-
             if (stop)
             {
                 // If we are allowed to ponder do not stop the search now but
@@ -566,27 +550,10 @@ namespace {
         TT.refresh(tte);
         ss->currentMove = ttMove; // Can be MOVE_NONE
 
-        // Update killers, history, and counter move on TT hit
-        if (    ttValue >= beta
-            &&  ttMove
-            && !pos.capture_or_promotion(ttMove)
-            && !inCheck)
-        {
-            if (ss->killers[0] != ttMove)
-            {
-                ss->killers[1] = ss->killers[0];
-                ss->killers[0] = ttMove;
-            }
-
-            Value bonus = Value(int(depth) * int(depth));
-            History.update(pos.moved_piece(ttMove), to_sq(ttMove), bonus);
+        // If ttMove is quiet, update killers, history, and counter move on TT hit
+        if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove) && !inCheck)
+            update_stats(pos, ss, ttMove, depth, NULL, 0);
 
-            if (is_ok((ss-1)->currentMove))
-            {
-                Square prevMoveSq = to_sq((ss-1)->currentMove);
-                Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, ttMove);
-            }
-        }
         return ttValue;
     }
 
@@ -1063,29 +1030,8 @@ moves_loop: // When in check and at SpNode search starts from here
              depth, bestMove, ss->staticEval);
 
     // Quiet best move: update killers, history and countermoves
-    if (    bestValue >= beta
-        && !pos.capture_or_promotion(bestMove)
-        && !inCheck)
-    {
-        if (ss->killers[0] != bestMove)
-        {
-            ss->killers[1] = ss->killers[0];
-            ss->killers[0] = bestMove;
-        }
-
-        // 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.moved_piece(bestMove), to_sq(bestMove), bonus);
-        for (int i = 0; i < quietCount - 1; ++i)
-        {
-            Move m = quietsSearched[i];
-            History.update(pos.moved_piece(m), to_sq(m), -bonus);
-        }
-
-        if (is_ok((ss-1)->currentMove))
-            Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, bestMove);
-    }
+    if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck)
+        update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1);
 
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
@@ -1318,6 +1264,35 @@ moves_loop: // When in check and at SpNode search starts from here
   }
 
 
+  // update_stats() updates killers, history and countermoves stats after a fail-high
+  // of a quiet move.
+
+  void update_stats(Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt) {
+
+    if (ss->killers[0] != move)
+    {
+        ss->killers[1] = ss->killers[0];
+        ss->killers[0] = move;
+    }
+
+    // Increase history value of the cut-off move and decrease all the other
+    // played quiet moves.
+    Value bonus = Value(int(depth) * int(depth));
+    History.update(pos.moved_piece(move), to_sq(move), bonus);
+    for (int i = 0; i < quietsCnt; ++i)
+    {
+        Move m = quiets[i];
+        History.update(pos.moved_piece(m), to_sq(m), -bonus);
+    }
+
+    if (is_ok((ss-1)->currentMove))
+    {
+        Square prevMoveSq = to_sq((ss-1)->currentMove);
+        Countermoves.update(pos.piece_on(prevMoveSq), prevMoveSq, move);
+    }
+  }
+
+
   // When playing with a strength handicap, choose best move among the MultiPV
   // set using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
 
@@ -1637,7 +1612,8 @@ void check_time() {
   Time::point elapsed = Time::now() - SearchTime;
   bool stillAtFirstMove =    Signals.firstRootMove
                          && !Signals.failedLowAtRoot
-                         &&  elapsed > TimeMgr.available_time();
+                         &&  elapsed > (TimeMgr.available_time() * 62) / 100
+                         &&  elapsed > IterationTime * 1.4;
 
   bool noMoreTime =   elapsed > TimeMgr.maximum_time() - 2 * TimerThread::Resolution
                    || stillAtFirstMove;