]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Reformat threads code
[stockfish] / src / search.cpp
index 189e11d0fe9991231393ebece1d657774f0520b1..f0bbf0fdecd013362a81f5037cb8d539e8c0495e 100644 (file)
@@ -24,7 +24,6 @@
 #include <iomanip>
 #include <iostream>
 #include <sstream>
-#include <vector>
 
 #include "book.h"
 #include "evaluate.h"
@@ -42,7 +41,7 @@ namespace Search {
 
   volatile SignalsType Signals;
   LimitsType Limits;
-  std::vector<Move> SearchMoves;
+  std::vector<RootMove> RootMoves;
   Position RootPosition;
 }
 
@@ -59,33 +58,6 @@ namespace {
   // Different node types, used as template parameter
   enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV };
 
-  // RootMove struct is used for moves at the root of the tree. For each root
-  // move we store a score, a node count, and a PV (really a refutation in the
-  // case of moves which fail low). Score is normally set at -VALUE_INFINITE for
-  // all non-pv moves.
-  struct RootMove {
-
-    RootMove(){}
-    RootMove(Move m) {
-      score = prevScore = -VALUE_INFINITE;
-      pv.push_back(m);
-      pv.push_back(MOVE_NONE);
-    }
-
-    bool operator<(const RootMove& m) const { return score < m.score; }
-    bool operator==(const Move& m) const { return pv[0] == m; }
-
-    void extract_pv_from_tt(Position& pos);
-    void insert_pv_in_tt(Position& pos);
-
-    Value score;
-    Value prevScore;
-    std::vector<Move> pv;
-  };
-
-
-  /// Constants
-
   // Lookup table to check if a Piece is a slider and its access function
   const bool Slidings[18] = { 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1 };
   inline bool piece_is_slider(Piece p) { return Slidings[p]; }
@@ -135,14 +107,14 @@ namespace {
     return (Depth) Reductions[PvNode][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)];
   }
 
-  // Easy move margin. An easy move candidate must be at least this much
-  // better than the second best move.
+  // Easy move margin. An easy move candidate must be at least this much 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
 
-  std::vector<RootMove> RootMoves;
   size_t MultiPV, UCIMultiPV, PVIdx;
   TimeManager TimeMgr;
   int BestMoveChanges;
@@ -151,8 +123,6 @@ namespace {
   History H;
 
 
-  /// Local functions
-
   template <NodeType NT>
   Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
 
@@ -197,19 +167,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_moved(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;
 
@@ -285,27 +255,24 @@ void Search::think() {
   TimeMgr.init(Limits, pos.startpos_ply_counter());
   TT.new_search();
   H.clear();
-  RootMoves.clear();
 
-  // 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()))
-          RootMoves.push_back(RootMove(ml.move()));
+  if (RootMoves.empty())
+  {
+      cout << "info depth 0 score "
+           << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW) << endl;
+
+      RootMoves.push_back(MOVE_NONE);
+      goto finalize;
+  }
 
   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 +315,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,11 +342,11 @@ 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
-  // before we are told to do so.
+  // When we reach max depth we arrive here even without Signals.stop is raised,
+  // but if we are pondering or in infinite search, we shouldn't print the best
+  // move before we are told to do so.
   if (!Signals.stop && (Limits.ponder || Limits.infinite))
       Threads.wait_for_stop_or_ponderhit();
 
@@ -408,16 +375,6 @@ namespace {
     bestValue = delta = -VALUE_INFINITE;
     ss->currentMove = MOVE_NULL; // Hack to skip update gains
 
-    // Handle the special case of a mated/stalemate position
-    if (RootMoves.empty())
-    {
-        cout << "info depth 0 score "
-             << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW) << endl;
-
-        RootMoves.push_back(MOVE_NONE);
-        return;
-    }
-
     // Iterative deepening loop until requested to stop or target depth reached
     while (!Signals.stop && ++depth <= MAX_PLY && (!Limits.maxDepth || depth <= Limits.maxDepth))
     {
@@ -518,7 +475,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
 
@@ -533,15 +490,15 @@ namespace {
                 stop = true;
 
             // Stop search early if one move seems to be much better than others
-            if (   depth >= 10
+            if (    depth >= 12
                 && !stop
-                && (   bestMoveNeverChanged
+                && (   (bestMoveNeverChanged &&  pos.captured_piece_type())
                     || elapsed_time() > (TimeMgr.available_time() * 40) / 100))
             {
                 Value rBeta = bestValue - EasyMoveMargin;
                 (ss+1)->excludedMove = RootMoves[0].pv[0];
                 (ss+1)->skipNullMove = true;
-                Value v = search<NonPV>(pos, ss+1, rBeta - 1, rBeta, (depth * ONE_PLY) / 2);
+                Value v = search<NonPV>(pos, ss+1, rBeta - 1, rBeta, (depth - 3) * ONE_PLY);
                 (ss+1)->skipNullMove = false;
                 (ss+1)->excludedMove = MOVE_NONE;
 
@@ -587,7 +544,7 @@ namespace {
     const bool RootNode = (NT == Root || NT == SplitPointRoot);
 
     assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
-    assert(PvNode == (alpha != beta - 1));
+    assert((alpha == beta - 1) || PvNode);
     assert(depth > DEPTH_ZERO);
     assert(pos.thread() >= 0 && pos.thread() < Threads.size());
 
@@ -616,22 +573,32 @@ namespace {
         thread.maxPly = ss->ply;
 
     // Step 1. Initialize node
-    if (!SpNode)
-    {
-        ss->currentMove = ss->bestMove = threatMove = (ss+1)->excludedMove = MOVE_NONE;
-        (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
-        (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
-    }
-    else
+    if (SpNode)
     {
-        sp = ss->sp;
         tte = NULL;
         ttMove = excludedMove = MOVE_NONE;
+        sp = ss->sp;
         threatMove = sp->threatMove;
+        bestValue = sp->bestValue;
+        moveCount = sp->moveCount; // Lock must be held here
+
+        assert(bestValue > -VALUE_INFINITE && moveCount > 0);
+
         goto split_point_start;
     }
+    else
+    {
+        ss->currentMove = ss->bestMove = threatMove = (ss+1)->excludedMove = MOVE_NONE;
+        (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
+        (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
+
+    }
 
     // Step 2. Check for aborted search and immediate draw
+    // Enforce node limit here. FIXME: This only works with 1 search thread.
+    if (Limits.maxNodes && pos.nodes_searched() >= Limits.maxNodes)
+        Signals.stop = true;
+
     if ((   Signals.stop
          || pos.is_draw<false>()
          || ss->ply > MAX_PLY) && !RootNode)
@@ -703,10 +670,10 @@ namespace {
     if (   (move = (ss-1)->currentMove) != MOVE_NULL
         && (ss-1)->eval != VALUE_NONE
         && ss->eval != VALUE_NONE
-        && pos.captured_piece_type() == NO_PIECE_TYPE
+        && !pos.captured_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);
     }
 
@@ -814,6 +781,7 @@ namespace {
         Depth rdepth = depth - ONE_PLY - 3 * ONE_PLY;
 
         assert(rdepth >= ONE_PLY);
+        assert((ss-1)->currentMove != MOVE_NONE);
 
         MovePicker mp(pos, ttMove, H, pos.captured_piece_type());
         CheckInfo ci(pos);
@@ -821,6 +789,7 @@ namespace {
         while ((move = mp.next_move()) != MOVE_NONE)
             if (pos.pl_move_is_legal(move, ci.pinned))
             {
+                ss->currentMove = move;
                 pos.do_move(move, st, ci, pos.move_gives_check(move, ci));
                 value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, rdepth);
                 pos.undo_move(move);
@@ -857,20 +826,13 @@ split_point_start: // At split points actual search starts from here
                            && !excludedMove // Recursive singular search is not allowed
                            && (tte->type() & VALUE_TYPE_LOWER)
                            && tte->depth() >= depth - 3 * ONE_PLY;
-    if (SpNode)
-    {
-        lock_grab(&(sp->lock));
-        bestValue = sp->bestValue;
-        moveCount = sp->moveCount;
-
-        assert(bestValue > -VALUE_INFINITE && moveCount > 0);
-    }
 
     // Step 11. Loop through moves
     // 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));
 
@@ -890,7 +852,7 @@ split_point_start: // At split points actual search starts from here
       if (SpNode)
       {
           moveCount = ++sp->moveCount;
-          lock_release(&(sp->lock));
+          lock_release(sp->lock);
       }
       else
           moveCount++;
@@ -961,7 +923,7 @@ split_point_start: // At split points actual search starts from here
               && (!threatMove || !connected_threat(pos, move, threatMove)))
           {
               if (SpNode)
-                  lock_grab(&(sp->lock));
+                  lock_grab(sp->lock);
 
               continue;
           }
@@ -971,12 +933,12 @@ 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_moved(move), to_sq(move));
 
           if (futilityValue < beta)
           {
               if (SpNode)
-                  lock_grab(&(sp->lock));
+                  lock_grab(sp->lock);
 
               continue;
           }
@@ -986,7 +948,7 @@ split_point_start: // At split points actual search starts from here
               && pos.see_sign(move) < 0)
           {
               if (SpNode)
-                  lock_grab(&(sp->lock));
+                  lock_grab(sp->lock);
 
               continue;
           }
@@ -1008,7 +970,7 @@ split_point_start: // At split points actual search starts from here
 
       // Step 15. Reduced depth search (LMR). If the move fails high will be
       // re-searched at full depth.
-      if (   depth > 3 * ONE_PLY
+      if (   depth > 4 * ONE_PLY
           && !isPvMove
           && !captureOrPromotion
           && !dangerous
@@ -1017,11 +979,10 @@ split_point_start: // At split points actual search starts from here
           &&  ss->killers[1] != move)
       {
           ss->reduction = reduction<PvNode>(depth, moveCount);
-          Depth d = newDepth - ss->reduction;
+          Depth d = std::max(newDepth - ss->reduction, ONE_PLY);
           alpha = SpNode ? sp->alpha : alpha;
 
-          value = d < ONE_PLY ? -qsearch<NonPV>(pos, ss+1, -(alpha+1), -alpha, DEPTH_ZERO)
-                              : - search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d);
+          value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d);
 
           doFullDepthSearch = (value > alpha && ss->reduction != DEPTH_ZERO);
           ss->reduction = DEPTH_ZERO;
@@ -1052,12 +1013,12 @@ split_point_start: // At split points actual search starts from here
       // Step 18. Check for new best move
       if (SpNode)
       {
-          lock_grab(&(sp->lock));
+          lock_grab(sp->lock);
           bestValue = sp->bestValue;
           alpha = sp->alpha;
       }
 
-      // Finished searching the move. If StopRequest is true, the search
+      // 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.
@@ -1118,7 +1079,7 @@ split_point_start: // At split points actual search starts from here
     // Step 20. Check for mate and stalemate
     // All legal moves have been searched and if there are no legal moves, it
     // must be mate or stalemate. Note that we can have a false positive in
-    // case of StopRequest or thread.cutoff_occurred() are set, but this is
+    // case of Signals.stop or thread.cutoff_occurred() are set, but this is
     // harmless because return value is discarded anyhow in the parent nodes.
     // If we are in a singular extension search then return a fail low score.
     if (!moveCount)
@@ -1155,25 +1116,17 @@ 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_moved(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_moved(m), to_sq(m), -bonus);
             }
         }
     }
 
-    if (SpNode)
-    {
-        // Here we have the lock still grabbed
-        sp->is_slave[pos.thread()] = false;
-        sp->nodes += pos.nodes_searched();
-        lock_release(&(sp->lock));
-    }
-
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
     return bestValue;
@@ -1191,7 +1144,7 @@ split_point_start: // At split points actual search starts from here
 
     assert(NT == PV || NT == NonPV);
     assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
-    assert(PvNode == (alpha != beta - 1));
+    assert((alpha == beta - 1) || PvNode);
     assert(depth <= DEPTH_ZERO);
     assert(pos.thread() >= 0 && pos.thread() < Threads.size());
 
@@ -1267,7 +1220,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 +1241,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,9 +1345,9 @@ 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);
-    them = flip(pos.side_to_move());
+    from = from_sq(move);
+    to = to_sq(move);
+    them = ~pos.side_to_move();
     ksq = pos.king_square(them);
     kingAtt = pos.attacks_from<KING>(ksq);
     pc = pos.piece_on(from);
@@ -1453,14 +1406,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 +1486,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)
@@ -1802,105 +1755,105 @@ split_point_start: // At split points actual search starts from here
     return best;
   }
 
+} // namespace
 
-  // 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 RootMove::extract_pv_from_tt(Position& pos) {
+/// RootMove::extract_pv_from_tt() builds a PV by adding moves from the TT table.
+/// We consider also failing high nodes and not only VALUE_TYPE_EXACT nodes so
+/// to allow to always have a ponder move even when we fail high at root, and
+/// a long PV to print that is important for position analysis.
 
-    StateInfo state[MAX_PLY_PLUS_2], *st = state;
-    TTEntry* tte;
-    int ply = 1;
-    Move m = pv[0];
-
-    assert(m != MOVE_NONE && pos.is_pseudo_legal(m));
-
-    pv.clear();
-    pv.push_back(m);
-    pos.do_move(m, *st++);
-
-    while (   (tte = TT.probe(pos.key())) != NULL
-           && tte->move() != MOVE_NONE
-           && pos.is_pseudo_legal(tte->move())
-           && pos.pl_move_is_legal(tte->move(), pos.pinned_pieces())
-           && ply < MAX_PLY
-           && (!pos.is_draw<false>() || ply < 2))
-    {
-        pv.push_back(tte->move());
-        pos.do_move(tte->move(), *st++);
-        ply++;
-    }
-    pv.push_back(MOVE_NONE);
+void RootMove::extract_pv_from_tt(Position& pos) {
+
+  StateInfo state[MAX_PLY_PLUS_2], *st = state;
+  TTEntry* tte;
+  int ply = 1;
+  Move m = pv[0];
+
+  assert(m != MOVE_NONE && pos.is_pseudo_legal(m));
+
+  pv.clear();
+  pv.push_back(m);
+  pos.do_move(m, *st++);
 
-    do pos.undo_move(pv[--ply]); while (ply);
+  while (   (tte = TT.probe(pos.key())) != NULL
+         && tte->move() != MOVE_NONE
+         && pos.is_pseudo_legal(tte->move())
+         && pos.pl_move_is_legal(tte->move(), pos.pinned_pieces())
+         && ply < MAX_PLY
+         && (!pos.is_draw<false>() || ply < 2))
+  {
+      pv.push_back(tte->move());
+      pos.do_move(tte->move(), *st++);
+      ply++;
   }
+  pv.push_back(MOVE_NONE);
 
+  do pos.undo_move(pv[--ply]); while (ply);
+}
 
-  // 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 RootMove::insert_pv_in_tt(Position& pos) {
+/// RootMove::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.
 
-    StateInfo state[MAX_PLY_PLUS_2], *st = state;
-    TTEntry* tte;
-    Key k;
-    Value v, m = VALUE_NONE;
-    int ply = 0;
+void RootMove::insert_pv_in_tt(Position& pos) {
 
-    assert(pv[ply] != MOVE_NONE && pos.is_pseudo_legal(pv[ply]));
+  StateInfo state[MAX_PLY_PLUS_2], *st = state;
+  TTEntry* tte;
+  Key k;
+  Value v, m = VALUE_NONE;
+  int ply = 0;
 
-    do {
-        k = pos.key();
-        tte = TT.probe(k);
+  assert(pv[ply] != MOVE_NONE && pos.is_pseudo_legal(pv[ply]));
 
-        // Don't overwrite existing correct entries
-        if (!tte || tte->move() != pv[ply])
-        {
-            v = (pos.in_check() ? VALUE_NONE : evaluate(pos, m));
-            TT.store(k, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, pv[ply], v, m);
-        }
-        pos.do_move(pv[ply], *st++);
+  do {
+      k = pos.key();
+      tte = TT.probe(k);
 
-    } while (pv[++ply] != MOVE_NONE);
+      // Don't overwrite existing correct entries
+      if (!tte || tte->move() != pv[ply])
+      {
+          v = (pos.in_check() ? VALUE_NONE : evaluate(pos, m));
+          TT.store(k, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, pv[ply], v, m);
+      }
+      pos.do_move(pv[ply], *st++);
 
-    do pos.undo_move(pv[--ply]); while (ply);
-  }
+  } while (pv[++ply] != MOVE_NONE);
 
-} // namespace
+  do pos.undo_move(pv[--ply]); while (ply);
+}
 
 
 /// Thread::idle_loop() is where the thread is parked when it has no work to do.
-/// The parameter 'sp', if non-NULL, is a pointer to an active SplitPoint object
-/// for which the thread is the master.
+/// The parameter 'master_sp', if non-NULL, is a pointer to an active SplitPoint
+/// object for which the thread is the master.
 
-void Thread::idle_loop(SplitPoint* sp) {
+void Thread::idle_loop(SplitPoint* sp_master) {
 
-  while (true)
+  // If this thread is the master of a split point and all slaves have
+  // finished their work at this split point, return from the idle loop.
+  while (!sp_master || sp_master->slavesMask)
   {
       // If we are not searching, wait for a condition to be signaled
       // instead of wasting CPU time polling for work.
       while (   do_sleep
-             || do_terminate
-             || (Threads.use_sleeping_threads() && !is_searching))
+             || do_exit
+             || (!is_searching && Threads.use_sleeping_threads()))
       {
-          assert((!sp && threadID) || Threads.use_sleeping_threads());
-
-          if (do_terminate)
+          if (do_exit)
           {
-              assert(!sp);
+              assert(!sp_master);
               return;
           }
 
           // Grab the lock to avoid races with Thread::wake_up()
-          lock_grab(&sleepLock);
+          lock_grab(sleepLock);
 
           // If we are master and all slaves have finished don't go to sleep
-          if (sp && Threads.split_point_finished(sp))
+          if (sp_master && !sp_master->slavesMask)
           {
-              lock_release(&sleepLock);
+              lock_release(sleepLock);
               break;
           }
 
@@ -1909,64 +1862,60 @@ void Thread::idle_loop(SplitPoint* sp) {
           // in the meanwhile, allocated us and sent the wake_up() call before we
           // had the chance to grab the lock.
           if (do_sleep || !is_searching)
-              cond_wait(&sleepCond, &sleepLock);
+              cond_wait(sleepCond, sleepLock);
 
-          lock_release(&sleepLock);
+          lock_release(sleepLock);
       }
 
       // If this thread has been assigned work, launch a search
       if (is_searching)
       {
-          assert(!do_terminate);
+          assert(!do_sleep && !do_exit);
 
           // Copy split point position and search stack and call search()
           Stack ss[MAX_PLY_PLUS_2];
-          SplitPoint* tsp = splitPoint;
-          Position pos(*tsp->pos, threadID);
-
-          memcpy(ss, tsp->ss - 1, 4 * sizeof(Stack));
-          (ss+1)->sp = tsp;
-
-          if (tsp->nodeType == Root)
-              search<SplitPointRoot>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
-          else if (tsp->nodeType == PV)
-              search<SplitPointPV>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
-          else if (tsp->nodeType == NonPV)
-              search<SplitPointNonPV>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
+          SplitPoint* sp = splitPoint;
+          Position pos(*sp->pos, threadID);
+
+          memcpy(ss, sp->ss - 1, 4 * sizeof(Stack));
+          (ss+1)->sp = sp;
+
+          lock_grab(sp->lock);
+
+          if (sp->nodeType == Root)
+              search<SplitPointRoot>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
+          else if (sp->nodeType == PV)
+              search<SplitPointPV>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
+          else if (sp->nodeType == NonPV)
+              search<SplitPointNonPV>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
           else
               assert(false);
 
           assert(is_searching);
 
+          // We return from search with lock held
+          sp->slavesMask &= ~(1ULL << threadID);
+          sp->nodes += pos.nodes_searched();
+          lock_release(sp->lock);
+
           is_searching = false;
 
           // Wake up master thread so to allow it to return from the idle loop in
           // case we are the last slave of the split point.
           if (   Threads.use_sleeping_threads()
-              && threadID != tsp->master
-              && !Threads[tsp->master].is_searching)
-              Threads[tsp->master].wake_up();
-      }
-
-      // If this thread is the master of a split point and all slaves have
-      // finished their work at this split point, return from the idle loop.
-      if (sp && Threads.split_point_finished(sp))
-      {
-          // Because sp->is_slave[] is reset under lock protection,
-          // be sure sp->lock has been released before to return.
-          lock_grab(&(sp->lock));
-          lock_release(&(sp->lock));
-          return;
+              && threadID != sp->master
+              && !Threads[sp->master].is_searching)
+              Threads[sp->master].wake_up();
       }
   }
 }
 
 
-/// 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,11 +1933,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)
-      || (Limits.maxTime && e >= Limits.maxTime)
-         /* missing nodes limit */ ) // FIXME
+  if (   (Limits.use_time_management() && noMoreTime)
+      || (Limits.maxTime && e >= Limits.maxTime))
       Signals.stop = true;
 }