]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Enable LMR for dangerous moves
[stockfish] / src / search.cpp
index 89ddfef6397b471ef00b87207dd9daa9338a8d0e..c85cdb5d689fcc1ee47f336812a1d9d310595ec0 100644 (file)
@@ -21,7 +21,6 @@
 #include <cassert>
 #include <cmath>
 #include <cstring>
-#include <exception>
 #include <iostream>
 #include <sstream>
 
@@ -85,7 +84,7 @@ namespace {
 
   size_t PVSize, PVIdx;
   TimeManager TimeMgr;
-  int BestMoveChanges;
+  float BestMoveChanges;
   Value DrawValue[COLOR_NB];
   HistoryStats History;
   GainsStats Gains;
@@ -105,8 +104,6 @@ namespace {
   bool refutes(const Position& pos, Move first, Move second);
   string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
 
-  class stop : public std::exception {};
-
   struct Skill {
     Skill(int l) : level(l), best(MOVE_NONE) {}
    ~Skill() {
@@ -156,9 +153,8 @@ void Search::init() {
   // Init futility move count array
   for (d = 0; d < 32; d++)
   {
-      FutilityMoveCounts[1][d] = int(3.001 + 0.3 * pow(double(d), 1.8));
-      FutilityMoveCounts[0][d] = d < 5 ? FutilityMoveCounts[1][d]
-                                       : 3 * FutilityMoveCounts[1][d] / 4;
+      FutilityMoveCounts[0][d] = int(3.001 + 0.3 * pow(double(d       ), 1.8)) * (d < 5 ? 4 : 3) / 4;
+      FutilityMoveCounts[1][d] = int(3.001 + 0.3 * pow(double(d + 0.98), 1.8));
   }
 }
 
@@ -307,14 +303,15 @@ namespace {
 
   void id_loop(Position& pos) {
 
-    Stack stack[MAX_PLY_PLUS_3], *ss = stack+2; // To allow referencing (ss-2)
-    int depth, prevBestMoveChanges;
+    Stack stack[MAX_PLY_PLUS_6], *ss = stack+2; // To allow referencing (ss-2)
+    int depth;
     Value bestValue, alpha, beta, delta;
 
     std::memset(ss-2, 0, 5 * sizeof(Stack));
     (ss-1)->currentMove = MOVE_NULL; // Hack to skip update gains
 
-    depth = BestMoveChanges = 0;
+    depth = 0;
+    BestMoveChanges = 0;
     bestValue = delta = alpha = -VALUE_INFINITE;
     beta = VALUE_INFINITE;
 
@@ -336,14 +333,14 @@ namespace {
     // Iterative deepening loop until requested to stop or target depth reached
     while (++depth <= MAX_PLY && !Signals.stop && (!Limits.depth || depth <= Limits.depth))
     {
+        // Age out PV variability metric
+        BestMoveChanges *= 0.8;
+
         // Save last iteration's scores before first PV line is searched and all
         // the move scores but the (new) PV are set to -VALUE_INFINITE.
         for (size_t i = 0; i < RootMoves.size(); i++)
             RootMoves[i].prevScore = RootMoves[i].score;
 
-        prevBestMoveChanges = BestMoveChanges; // Only sensible when PVSize == 1
-        BestMoveChanges = 0;
-
         // MultiPV loop. We perform a full root search for each PV line
         for (PVIdx = 0; PVIdx < PVSize; PVIdx++)
         {
@@ -359,9 +356,7 @@ namespace {
             // research with bigger window until not failing high/low anymore.
             while (true)
             {
-                try {
-                    bestValue = search<Root>(pos, ss, alpha, beta, depth * ONE_PLY, false);
-                } catch (stop&) {}
+                bestValue = search<Root>(pos, ss, alpha, beta, depth * ONE_PLY, false);
 
                 // Bring to front the best move. It is critical that sorting is
                 // done with a stable algorithm because all the values but the first
@@ -443,7 +438,7 @@ namespace {
 
             // Take in account some extra time if the best move has changed
             if (depth > 4 && depth < 50 &&  PVSize == 1)
-                TimeMgr.pv_instability(BestMoveChanges, prevBestMoveChanges);
+                TimeMgr.pv_instability(BestMoveChanges);
 
             // Stop search if most of available time is already consumed. We
             // probably don't have enough time to search the first move at the
@@ -546,13 +541,10 @@ namespace {
     if (PvNode && thisThread->maxPly < ss->ply)
         thisThread->maxPly = ss->ply;
 
-    if (Signals.stop || thisThread->cutoff_occurred())
-        throw stop();
-
     if (!RootNode)
     {
         // Step 2. Check for aborted search and immediate draw
-        if (pos.is_draw() || ss->ply > MAX_PLY)
+        if (Signals.stop || pos.is_draw() || ss->ply > MAX_PLY)
             return DrawValue[pos.side_to_move()];
 
         // Step 3. Mate distance pruning. Even if we mate at the next move our score
@@ -672,7 +664,7 @@ namespace {
     // Step 8. Null move search with verification search (is omitted in PV nodes)
     if (   !PvNode
         && !ss->skipNullMove
-        &&  depth > ONE_PLY
+        &&  depth >= 2 * ONE_PLY
         &&  eval >= beta
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
         &&  pos.non_pawn_material(pos.side_to_move()))
@@ -949,7 +941,6 @@ moves_loop: // When in check and at SpNode search starts from here
       if (    depth > 3 * ONE_PLY
           && !pvMove
           && !captureOrPromotion
-          && !dangerous
           &&  move != ttMove
           &&  move != ss->killers[0]
           &&  move != ss->killers[1])
@@ -1007,6 +998,13 @@ moves_loop: // When in check and at SpNode search starts from here
           alpha = splitPoint->alpha;
       }
 
+      // Finished searching the move. If Signals.stop is true, the search
+      // was aborted because the user interrupted the search or because we
+      // ran out of time. In this case, the return value of the search cannot
+      // be trusted, and we don't update the best move and/or PV.
+      if (Signals.stop || thisThread->cutoff_occurred())
+          return value; // To avoid returning VALUE_INFINITE
+
       if (RootNode)
       {
           RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move);
@@ -1232,6 +1230,7 @@ moves_loop: // When in check and at SpNode search starts from here
           && !givesCheck
           &&  move != ttMove
           &&  type_of(move) != PROMOTION
+          &&  futilityBase > -VALUE_KNOWN_WIN
           && !pos.is_passed_pawn_push(move))
       {
           futilityValue =  futilityBase
@@ -1577,7 +1576,7 @@ moves_loop: // When in check and at SpNode search starts from here
 
 void RootMove::extract_pv_from_tt(Position& pos) {
 
-  StateInfo state[MAX_PLY_PLUS_3], *st = state;
+  StateInfo state[MAX_PLY_PLUS_6], *st = state;
   const TTEntry* tte;
   int ply = 0;
   Move m = pv[0];
@@ -1610,7 +1609,7 @@ void RootMove::extract_pv_from_tt(Position& pos) {
 
 void RootMove::insert_pv_in_tt(Position& pos) {
 
-  StateInfo state[MAX_PLY_PLUS_3], *st = state;
+  StateInfo state[MAX_PLY_PLUS_6], *st = state;
   const TTEntry* tte;
   int ply = 0;
 
@@ -1685,7 +1684,7 @@ void Thread::idle_loop() {
 
           Threads.mutex.unlock();
 
-          Stack stack[MAX_PLY_PLUS_3], *ss = stack+2; // To allow referencing (ss-2)
+          Stack stack[MAX_PLY_PLUS_6], *ss = stack+2; // To allow referencing (ss-2)
           Position pos(*sp->pos, this);
 
           std::memcpy(ss-2, sp->ss-2, 5 * sizeof(Stack));
@@ -1697,27 +1696,22 @@ void Thread::idle_loop() {
 
           activePosition = &pos;
 
-          try {
-              switch (sp->nodeType) {
-              case Root:
-                  search<SplitPointRoot>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
-                  break;
-              case PV:
-                  search<SplitPointPV>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
-                  break;
-              case NonPV:
-                  search<SplitPointNonPV>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
-                  break;
-              default:
-                  assert(false);
-              }
-
-              assert(searching);
-          }
-          catch (stop&) {
-              sp->mutex.lock(); // Exception is thrown out of lock
+          switch (sp->nodeType) {
+          case Root:
+              search<SplitPointRoot>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
+              break;
+          case PV:
+              search<SplitPointPV>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
+              break;
+          case NonPV:
+              search<SplitPointNonPV>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
+              break;
+          default:
+              assert(false);
           }
 
+          assert(searching);
+
           searching = false;
           activePosition = NULL;
           sp->slavesMask &= ~(1ULL << idx);