]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Move time related global variables under TimeManager
[stockfish] / src / search.cpp
index d1642827f540263686c57b5100b98d0e268aa2fc..fa7052d0dc0c2605201a17bd283742541e1c3c59 100644 (file)
@@ -38,6 +38,7 @@
 #include "lock.h"
 #include "san.h"
 #include "search.h"
+#include "timeman.h"
 #include "thread.h"
 #include "tt.h"
 #include "ucioption.h"
@@ -90,7 +91,7 @@ namespace {
 
     template <bool Fake>
     void split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
-               Depth depth, bool mateThreat, int* moveCount, MovePicker* mp, bool pvNode);
+               Depth depth, Move threatMove, bool mateThreat, int* moveCount, MovePicker* mp, bool pvNode);
 
   private:
     friend void poll();
@@ -198,7 +199,7 @@ namespace {
   Depth PassedPawnExtension[2], PawnEndgameExtension[2], MateThreatExtension[2];
 
   // Minimum depth for use of singular extension
-  const Depth SingularExtensionDepth[2] = { 8 * OnePly /* non-PV */, 6 * OnePly /* PV */};
+  const Depth SingularExtensionDepth[2] = { 7 * OnePly /* non-PV */, 6 * OnePly /* PV */};
 
   // If the TT move is at least SingularExtensionMargin better then the
   // remaining ones we will extend it.
@@ -250,10 +251,10 @@ namespace {
   int MultiPV;
 
   // Time managment variables
-  int SearchStartTime, MaxNodes, MaxDepth, MaxSearchTime;
-  int AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
+  int SearchStartTime, MaxNodes, MaxDepth, ExactMaxTime;
   bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
   bool FirstRootMove, AbortSearch, Quit, AspirationFailLow;
+  TimeManager TimeMgr;
 
   // Log file
   bool UseLogFile;
@@ -309,6 +310,8 @@ namespace {
   void wait_for_stop_or_ponderhit();
   void init_ss_array(SearchStack* ss, int size);
   void print_pv_info(const Position& pos, Move pv[], Value alpha, Value beta, Value value);
+  void insert_pv_in_tt(const Position& pos, Move pv[]);
+  void extract_pv_from_tt(const Position& pos, Move bestMove, Move pv[]);
 
 #if !defined(_MSC_VER)
   void *init_thread(void *threadID);
@@ -342,8 +345,8 @@ void init_search() {
   // Init reductions array
   for (hd = 1; hd < 64; hd++) for (mc = 1; mc < 64; mc++)
   {
-      double    pvRed = log(double(hd)) * log(double(mc)) / 3.0;
-      double nonPVRed = log(double(hd)) * log(double(mc)) / 1.5;
+      double    pvRed = 0.33 + log(double(hd)) * log(double(mc)) / 4.5;
+      double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25;
       ReductionMatrix[PV][hd][mc]    = (int8_t) (   pvRed >= 1.0 ? floor(   pvRed * int(OnePly)) : 0);
       ReductionMatrix[NonPV][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(OnePly)) : 0);
   }
@@ -358,24 +361,6 @@ void init_search() {
 }
 
 
-// SearchStack::init() initializes a search stack entry.
-// Called at the beginning of search() when starting to examine a new node.
-void SearchStack::init() {
-
-  currentMove = threatMove = bestMove = MOVE_NONE;
-  reduction = Depth(0);
-  eval = VALUE_NONE;
-}
-
-// SearchStack::initKillers() initializes killers for a search stack entry
-void SearchStack::initKillers() {
-
-  mateKiller = MOVE_NONE;
-  for (int i = 0; i < KILLER_MAX; i++)
-      killers[i] = MOVE_NONE;
-}
-
-
 /// perft() is our utility to verify move generation is bug free. All the legal
 /// moves up to given depth are generated and counted and the sum returned.
 
@@ -416,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;
-  MaxSearchTime = AbsoluteMaxSearchTime = ExtraSearchTime = 0;
   NodesSincePoll = 0;
   TM.resetNodeCounters();
   SearchStartTime = get_system_time();
@@ -488,40 +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)
-  {
-      if (!movesToGo) // Sudden death time control
-      {
-          if (myIncrement)
-          {
-              MaxSearchTime = myTime / 30 + myIncrement;
-              AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
-          }
-          else // Blitz game without increment
-          {
-              MaxSearchTime = myTime / 30;
-              AbsoluteMaxSearchTime = myTime / 8;
-          }
-      }
-      else // (x moves) / (y minutes)
-      {
-          if (movesToGo == 1)
-          {
-              MaxSearchTime = myTime / 2;
-              AbsoluteMaxSearchTime = (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
-          }
-          else
-          {
-              MaxSearchTime = myTime / Min(movesToGo, 20);
-              AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
-          }
-      }
-
-      if (get_option_value_bool("Ponder"))
-      {
-          MaxSearchTime += MaxSearchTime / 4;
-          MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
-      }
-  }
+      TimeMgr.update(myTime, myIncrement, movesToGo, pos.startpos_ply_counter());
 
   // Set best NodesBetweenPolls interval to avoid lagging under
   // heavy time pressure.
@@ -632,7 +583,7 @@ namespace {
 
         // Write PV to transposition table, in case the relevant entries have
         // been overwritten during the search.
-        TT.insert_pv(p, pv);
+        insert_pv_in_tt(p, pv);
 
         if (AbortSearch)
             break; // Value cannot be trusted. Break out immediately!
@@ -665,20 +616,20 @@ namespace {
             if (   Iteration >= 8
                 && EasyMove == pv[0]
                 && (  (   rml.get_move_cumulative_nodes(0) > (nodes * 85) / 100
-                       && current_search_time() > MaxSearchTime / 16)
+                       && current_search_time() > TimeMgr.optimumSearchTime / 16)
                     ||(   rml.get_move_cumulative_nodes(0) > (nodes * 98) / 100
-                       && current_search_time() > MaxSearchTime / 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]   * (MaxSearchTime / 2)
-                                + BestMoveChangesByIteration[Iteration-1] * (MaxSearchTime / 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() > ((MaxSearchTime + ExtraSearchTime) * 80) / 128)
+            if (current_search_time() > (TimeMgr.available_time() * 80) / 128)
                 stopSearch = true;
 
             if (stopSearch)
@@ -764,15 +715,16 @@ namespace {
     beta = *betaPtr;
     isCheck = pos.is_check();
 
-    // Step 1. Initialize node and poll (omitted at root, init_ss_array() has already initialized root node)
+    // Step 1. Initialize node (polling is omitted at root)
+    ss->currentMove = ss->bestMove = MOVE_NONE;
+
     // Step 2. Check for aborted search (omitted at root)
     // Step 3. Mate distance pruning (omitted at root)
     // Step 4. Transposition table lookup (omitted at root)
 
     // Step 5. Evaluate the position statically
     // At root we do this only to get reference value for child nodes
-    if (!isCheck)
-        ss->eval = evaluate(pos, ei);
+    ss->eval = isCheck ? VALUE_NONE : evaluate(pos, ei);
 
     // Step 6. Razoring (omitted at root)
     // Step 7. Static null move pruning (omitted at root)
@@ -898,7 +850,7 @@ namespace {
                 // the score before research in case we run out of time while researching.
                 rml.set_move_score(i, value);
                 ss->bestMove = move;
-                TT.extract_pv(pos, move, pv, PLY_MAX);
+                extract_pv_from_tt(pos, move, pv);
                 rml.set_move_pv(i, pv);
 
                 // Print information to the standard output
@@ -938,7 +890,7 @@ namespace {
                 // Update PV
                 rml.set_move_score(i, value);
                 ss->bestMove = move;
-                TT.extract_pv(pos, move, pv, PLY_MAX);
+                extract_pv_from_tt(pos, move, pv);
                 rml.set_move_pv(i, pv);
 
                 if (MultiPV == 1)
@@ -1017,9 +969,9 @@ namespace {
     Move movesSearched[256];
     EvalInfo ei;
     StateInfo st;
-    const TTEntry* tte;
+    const TTEntry *tte, *ttx;
     Key posKey;
-    Move ttMove, move, excludedMove;
+    Move ttMove, move, excludedMove, threatMove;
     Depth ext, newDepth;
     Value bestValue, value, oldAlpha;
     Value refinedValue, nullValue, futilityValueScaled; // Non-PV specific
@@ -1032,8 +984,8 @@ namespace {
 
     // Step 1. Initialize node and poll. Polling can abort search
     TM.incrementNodeCounter(threadID);
-    ss->init();
-    (ss+2)->initKillers();
+    ss->currentMove = ss->bestMove = threatMove = MOVE_NONE;
+    (ss+2)->killers[0] = (ss+2)->killers[1] = (ss+2)->mateKiller = MOVE_NONE;
 
     if (threadID == 0 && ++NodesSincePoll > NodesBetweenPolls)
     {
@@ -1077,27 +1029,32 @@ namespace {
         // Refresh tte entry to avoid aging
         TT.store(posKey, tte->value(), tte->type(), tte->depth(), ttMove, tte->static_value(), tte->king_danger());
 
-        ss->currentMove = ttMove; // Can be MOVE_NONE
+        ss->bestMove = ttMove; // Can be MOVE_NONE
         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 && 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);
+        assert(tte->static_value() != VALUE_NONE);
 
-        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
+    {
+        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
         &&  depth < RazorDepth
@@ -1108,10 +1065,6 @@ namespace {
         && !value_is_mate(beta)
         && !pos.has_pawn_on_7th(pos.side_to_move()))
     {
-        // Pass ss->eval to qsearch() and avoid an evaluate call
-        if (!tte || tte->static_value() == VALUE_NONE)
-            TT.store(posKey, ss->eval, VALUE_TYPE_EXACT, Depth(-127*OnePly), MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]);
-
         Value rbeta = beta - razor_margin(depth);
         Value v = qsearch<NonPV>(pos, ss, rbeta-1, rbeta, Depth(0), ply);
         if (v < rbeta)
@@ -1126,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);
@@ -1139,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()))
     {
@@ -1189,10 +1142,10 @@ namespace {
             if (nullValue == value_mated_in(ply + 2))
                 mateThreat = true;
 
-            ss->threatMove = (ss+1)->currentMove;
+            threatMove = (ss+1)->bestMove;
             if (   depth < ThreatDepth
                 && (ss-1)->reduction
-                && connected_moves(pos, (ss-1)->currentMove, ss->threatMove))
+                && connected_moves(pos, (ss-1)->currentMove, threatMove))
                 return beta - 1;
         }
     }
@@ -1219,9 +1172,11 @@ namespace {
     // Initialize a MovePicker object for the current position
     MovePicker mp = MovePicker(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
     CheckInfo ci(pos);
+    ss->bestMove = MOVE_NONE;
     singleEvasion = isCheck && mp.number_of_evasions() == 1;
     singularExtensionNode =   depth >= SingularExtensionDepth[PvNode]
-                           && tte && tte->move()
+                           && tte
+                           && tte->move()
                            && !excludedMove // Do not allow recursive singular extension search
                            && is_lower_bound(tte->type())
                            && tte->depth() >= depth - 3 * OnePly;
@@ -1251,9 +1206,22 @@ namespace {
           && move == tte->move()
           && ext < OnePly)
       {
+          // Avoid to do an expensive singular extension search on nodes where
+          // such search have already been done in the past, so assume the last
+          // singular extension search result is still valid.
+          if (  !PvNode
+              && depth < SingularExtensionDepth[PvNode] + 5 * OnePly
+              && (ttx = TT.retrieve(pos.get_exclusion_key())) != NULL)
+          {
+              if (is_upper_bound(ttx->type()))
+                  ext = OnePly;
+
+              singularExtensionNode = false;
+          }
+
           Value ttValue = value_from_tt(tte->value(), ply);
 
-          if (abs(ttValue) < VALUE_KNOWN_WIN)
+          if (singularExtensionNode && abs(ttValue) < VALUE_KNOWN_WIN)
           {
               Value b = ttValue - SingularExtensionMargin;
               ss->excludedMove = move;
@@ -1261,6 +1229,7 @@ namespace {
               Value v = search<NonPV>(pos, ss, b - 1, b, depth / 2, ply);
               ss->skipNullMove = false;
               ss->excludedMove = MOVE_NONE;
+              ss->bestMove = MOVE_NONE;
               if (v < b)
                   ext = OnePly;
           }
@@ -1281,7 +1250,7 @@ namespace {
       {
           // Move count based pruning
           if (   moveCount >= futility_move_count(depth)
-              && !(ss->threatMove && connected_threat(pos, move, ss->threatMove))
+              && !(threatMove && connected_threat(pos, move, threatMove))
               && bestValue > value_mated_in(PLY_MAX))
               continue;
 
@@ -1370,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))
@@ -1389,7 +1358,7 @@ namespace {
           && !TM.thread_should_stop(threadID)
           && Iteration <= 99)
           TM.split<FakeSplit>(pos, ss, ply, &alpha, beta, &bestValue, depth,
-                              mateThreat, &moveCount, &mp, PvNode);
+                              threatMove, mateThreat, &moveCount, &mp, PvNode);
     }
 
     // Step 19. Check for mate and stalemate
@@ -1397,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,
@@ -1405,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)
@@ -1450,7 +1419,6 @@ namespace {
 
     TM.incrementNodeCounter(pos.thread());
     ss->bestMove = ss->currentMove = MOVE_NONE;
-    ss->eval = VALUE_NONE;
 
     // Check for an instant draw or maximum ply reached
     if (pos.is_draw() || ply >= PLY_MAX - 1)
@@ -1463,7 +1431,7 @@ namespace {
 
     if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
     {
-        ss->currentMove = ttMove; // Can be MOVE_NONE
+        ss->bestMove = ttMove; // Can be MOVE_NONE
         return value_from_tt(tte->value(), ply);
     }
 
@@ -1473,12 +1441,15 @@ namespace {
     if (isCheck)
     {
         bestValue = futilityBase = -VALUE_INFINITE;
+        ss->eval = VALUE_NONE;
         deepChecks = enoughMaterial = false;
     }
     else
     {
-        if (tte && tte->static_value() != VALUE_NONE)
+        if (tte)
         {
+            assert(tte->static_value() != VALUE_NONE);
+
             ei.kingDanger[pos.side_to_move()] = tte->king_danger();
             bestValue = tte->static_value();
         }
@@ -1492,7 +1463,7 @@ namespace {
         if (bestValue >= beta)
         {
             if (!tte)
-                TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, Depth(-127*OnePly), MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]);
+                TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, ei.kingDanger[pos.side_to_move()]);
 
             return bestValue;
         }
@@ -1588,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
@@ -1662,7 +1633,7 @@ namespace {
       {
           // Move count based pruning
           if (   moveCount >= futility_move_count(sp->depth)
-              && !(ss->threatMove && connected_threat(pos, move, ss->threatMove))
+              && !(sp->threatMove && connected_threat(pos, move, sp->threatMove))
               && sp->bestValue > value_mated_in(PLY_MAX))
           {
               lock_grab(&(sp->lock));
@@ -1873,10 +1844,8 @@ namespace {
 
   bool move_is_killer(Move m, SearchStack* ss) {
 
-      const Move* k = ss->killers;
-      for (int i = 0; i < KILLER_MAX; i++, k++)
-          if (*k == m)
-              return true;
+      if (ss->killers[0] == m || ss->killers[1] == m)
+          return true;
 
       return false;
   }
@@ -2010,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);
 
@@ -2053,9 +2021,7 @@ namespace {
     if (m == ss->killers[0])
         return;
 
-    for (int i = KILLER_MAX - 1; i > 0; i--)
-        ss->killers[i] = ss->killers[i - 1];
-
+    ss->killers[1] = ss->killers[0];
     ss->killers[0] = m;
   }
 
@@ -2069,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));
   }
 
@@ -2170,9 +2135,9 @@ namespace {
 
     bool stillAtFirstMove =    FirstRootMove
                            && !AspirationFailLow
-                           &&  t > MaxSearchTime + ExtraSearchTime;
+                           &&  t > TimeMgr.available_time();
 
-    bool noMoreTime =   t > AbsoluteMaxSearchTime
+    bool noMoreTime =   t > TimeMgr.maximumSearchTime
                      || stillAtFirstMove;
 
     if (   (Iteration >= 3 && UseTimeManagement && noMoreTime)
@@ -2193,9 +2158,9 @@ namespace {
 
     bool stillAtFirstMove =    FirstRootMove
                            && !AspirationFailLow
-                           &&  t > MaxSearchTime + ExtraSearchTime;
+                           &&  t > TimeMgr.available_time();
 
-    bool noMoreTime =   t > AbsoluteMaxSearchTime
+    bool noMoreTime =   t > TimeMgr.maximumSearchTime
                      || stillAtFirstMove;
 
     if (Iteration >= 3 && UseTimeManagement && (noMoreTime || StopOnPonderhit))
@@ -2212,12 +2177,10 @@ namespace {
     {
         ss->excludedMove = MOVE_NONE;
         ss->skipNullMove = false;
+        ss->reduction = Depth(0);
 
         if (i < 3)
-        {
-            ss->init();
-            ss->initKillers();
-        }
+            ss->killers[0] = ss->killers[1] = ss->mateKiller = MOVE_NONE;
     }
   }
 
@@ -2278,6 +2241,61 @@ namespace {
   }
 
 
+  // insert_pv_in_tt() is called at the end of a search iteration, and inserts
+  // the PV back into the TT. This makes sure the old PV moves are searched
+  // first, even if the old TT entries have been overwritten.
+
+  void insert_pv_in_tt(const Position& pos, Move pv[]) {
+
+    StateInfo st;
+    TTEntry* tte;
+    Position p(pos, pos.thread());
+    EvalInfo ei;
+    Value v;
+
+    for (int i = 0; pv[i] != MOVE_NONE; i++)
+    {
+        tte = TT.retrieve(p.get_key());
+        if (!tte || tte->move() != pv[i])
+        {
+            v = (p.is_check() ? VALUE_NONE : evaluate(p, ei));
+            TT.store(p.get_key(), VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, pv[i], v, ei.kingDanger[pos.side_to_move()]);
+        }
+        p.do_move(pv[i], st);
+    }
+  }
+
+
+  // extract_pv_from_tt() builds a PV by adding moves from the transposition table.
+  // We consider also failing high nodes and not only VALUE_TYPE_EXACT nodes. This
+  // allow to always have a ponder move even when we fail high at root and also a
+  // long PV to print that is important for position analysis.
+
+  void extract_pv_from_tt(const Position& pos, Move bestMove, Move pv[]) {
+
+    StateInfo st;
+    TTEntry* tte;
+    Position p(pos, pos.thread());
+    int ply = 0;
+
+    assert(bestMove != MOVE_NONE);
+
+    pv[ply] = bestMove;
+    p.do_move(pv[ply++], st);
+
+    while (   (tte = TT.retrieve(p.get_key())) != NULL
+           && tte->move() != MOVE_NONE
+           && move_is_legal(p, tte->move())
+           && ply < PLY_MAX
+           && (!p.is_draw() || ply < 2))
+    {
+        pv[ply] = tte->move();
+        p.do_move(pv[ply++], st);
+    }
+    pv[ply] = MOVE_NONE;
+  }
+
+
   // init_thread() is the function which is called when a new thread is
   // launched. It simply calls the idle_loop() function with the supplied
   // threadID. There are two versions of this function; one for POSIX
@@ -2433,8 +2451,8 @@ namespace {
 #endif
 
     // Initialize global locks
-    lock_init(&MPLock, NULL);
-    lock_init(&WaitLock, NULL);
+    lock_init(&MPLock);
+    lock_init(&WaitLock);
 
 #if !defined(_MSC_VER)
     pthread_cond_init(&WaitCond, NULL);
@@ -2446,7 +2464,7 @@ namespace {
     // Initialize splitPoints[] locks
     for (i = 0; i < MAX_THREADS; i++)
         for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
-            lock_init(&(threads[i].splitPoints[j].lock), NULL);
+            lock_init(&(threads[i].splitPoints[j].lock));
 
     // Will be set just before program exits to properly end the threads
     AllThreadsShouldExit = false;
@@ -2589,8 +2607,8 @@ namespace {
 
   template <bool Fake>
   void ThreadsManager::split(const Position& p, SearchStack* ss, int ply, Value* alpha,
-                             const Value beta, Value* bestValue, Depth depth, bool mateThreat,
-                             int* moveCount, MovePicker* mp, bool pvNode) {
+                             const Value beta, Value* bestValue, Depth depth, Move threatMove,
+                             bool mateThreat, int* moveCount, MovePicker* mp, bool pvNode) {
     assert(p.is_ok());
     assert(ply > 0 && ply < PLY_MAX);
     assert(*bestValue >= -VALUE_INFINITE);
@@ -2623,6 +2641,7 @@ namespace {
     splitPoint.stopRequest = false;
     splitPoint.ply = ply;
     splitPoint.depth = depth;
+    splitPoint.threatMove = threatMove;
     splitPoint.mateThreat = mateThreat;
     splitPoint.alpha = *alpha;
     splitPoint.beta = beta;
@@ -2737,6 +2756,11 @@ namespace {
     StateInfo st;
     bool includeAllMoves = (searchMoves[0] == MOVE_NONE);
 
+    // Initialize search stack
+    init_ss_array(ss, PLY_MAX_PLUS_2);
+    ss[0].currentMove = ss[0].bestMove = MOVE_NONE;
+    ss[0].eval = VALUE_NONE;
+
     // Generate all legal moves
     MoveStack* last = generate_moves(pos, mlist);
 
@@ -2752,8 +2776,8 @@ namespace {
             continue;
 
         // Find a quick score for the move
-        init_ss_array(ss, PLY_MAX_PLUS_2);
         pos.do_move(cur->move, st);
+        ss[0].currentMove = cur->move;
         moves[count].move = cur->move;
         moves[count].score = -qsearch<PV>(pos, ss+1, -VALUE_INFINITE, VALUE_INFINITE, Depth(0), 1);
         moves[count].pv[0] = cur->move;