]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Retire move_attacks_square()
[stockfish] / src / search.cpp
index 163df7b4ec4b6f4f017fbe13318a0320a820c15e..2b51a698b0de3e40c8208255251a92fc0149faf0 100644 (file)
@@ -41,7 +41,8 @@ namespace Search {
   volatile SignalsType Signals;
   LimitsType Limits;
   std::vector<RootMove> RootMoves;
-  Position RootPosition;
+  Position RootPos;
+  Color RootColor;
   Time::point SearchTime;
   StateStackPtr SetupStates;
 }
@@ -55,6 +56,9 @@ namespace {
   // Set to true to force running with one thread. Used for debugging
   const bool FakeSplit = false;
 
+  // This is the minimum interval in msec between two check_time() calls
+  const int TimerResolution = 5;
+
   // Different node types, used as template parameter
   enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV };
 
@@ -62,28 +66,9 @@ namespace {
   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]; }
 
-  // Maximum depth for razoring
-  const Depth RazorDepth = 4 * ONE_PLY;
-
   // Dynamic razoring margin based on depth
   inline Value razor_margin(Depth d) { return Value(512 + 16 * int(d)); }
 
-  // Maximum depth for use of dynamic threat detection when null move fails low
-  const Depth ThreatDepth = 5 * ONE_PLY;
-
-  // Minimum depth for use of internal iterative deepening
-  const Depth IIDDepth[] = { 8 * ONE_PLY, 5 * ONE_PLY };
-
-  // At Non-PV nodes we do an internal iterative deepening search
-  // when the static evaluation is bigger then beta - IIDMargin.
-  const Value IIDMargin = Value(256);
-
-  // Minimum depth for use of singular extension
-  const Depth SingularExtensionDepth[] = { 8 * ONE_PLY, 6 * ONE_PLY };
-
-  // Futility margin for quiescence search
-  const Value FutilityMarginQS = Value(128);
-
   // Futility lookup tables (initialized at startup) and their access functions
   Value FutilityMargins[16][64]; // [depth][moveNumber]
   int FutilityMoveCounts[32];    // [depth]
@@ -94,11 +79,6 @@ namespace {
                            : 2 * VALUE_INFINITE;
   }
 
-  inline int futility_move_count(Depth d) {
-
-    return d < 16 * ONE_PLY ? FutilityMoveCounts[d] : MAX_MOVES;
-  }
-
   // Reduction lookup tables (initialized at startup) and their access function
   int8_t Reductions[2][64][64]; // [pv][depth][moveNumber]
 
@@ -107,22 +87,12 @@ 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.
-  const Value EasyMoveMargin = Value(0x150);
-
-  // This is the minimum interval in msec between two check_time() calls
-  const int TimerResolution = 5;
-
-
-  size_t MultiPV, UCIMultiPV, PVIdx;
+  size_t PVSize, PVIdx;
   TimeManager TimeMgr;
   int BestMoveChanges;
-  int SkillLevel;
-  bool SkillLevelEnabled, Chess960;
+  Value DrawValue[COLOR_NB];
   History H;
 
-
   template <NodeType NT>
   Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
 
@@ -130,39 +100,28 @@ namespace {
   Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
 
   void id_loop(Position& pos);
-  bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta);
+  bool check_is_dangerous(Positionpos, Move move, Value futilityBase, Value beta);
   bool connected_moves(const Position& pos, Move m1, Move m2);
   Value value_to_tt(Value v, int ply);
   Value value_from_tt(Value v, int ply);
-  bool can_return_tt(const TTEntry* tte, Depth depth, Value ttValue, Value beta);
   bool connected_threat(const Position& pos, Move m, Move threat);
-  Value refine_eval(const TTEntry* tte, Value ttValue, Value defaultEval);
-  Move do_skill_level();
   string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
 
-  // is_dangerous() checks whether a move belongs to some classes of known
-  // 'dangerous' moves so that we avoid to prune it.
-  FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) {
+  struct Skill {
+    Skill(int l) : level(l), best(MOVE_NONE) {}
+   ~Skill() {
+      if (enabled()) // Swap best PV line with the sub-optimal one
+          std::swap(RootMoves[0], *std::find(RootMoves.begin(),
+                    RootMoves.end(), best ? best : pick_move()));
+    }
 
-    // Castle move?
-    if (type_of(m) == CASTLE)
-        return true;
+    bool enabled() const { return level < 20; }
+    bool time_to_pick(int depth) const { return depth == 1 + level; }
+    Move pick_move();
 
-    // Passed pawn move?
-    if (   type_of(pos.piece_moved(m)) == PAWN
-        && pos.pawn_is_passed(pos.side_to_move(), to_sq(m)))
-        return true;
-
-    // Entering a pawn endgame?
-    if (    captureOrPromotion
-        &&  type_of(pos.piece_on(to_sq(m))) != PAWN
-        &&  type_of(m) == NORMAL
-        && (  pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
-            - PieceValue[Mg][pos.piece_on(to_sq(m))] == VALUE_ZERO))
-        return true;
-
-    return false;
-  }
+    int level;
+    Move best;
+  };
 
 } // namespace
 
@@ -190,7 +149,7 @@ void Search::init() {
 
   // Init futility move count array
   for (d = 0; d < 32; d++)
-      FutilityMoveCounts[d] = int(3.001 + 0.25 * pow(d, 2.0));
+      FutilityMoveCounts[d] = int(3.001 + 0.25 * pow(double(d), 2.0));
 }
 
 
@@ -220,31 +179,28 @@ size_t Search::perft(Position& pos, Depth depth) {
 
 /// Search::think() is the external interface to Stockfish's search, and is
 /// called by the main thread when the program receives the UCI 'go' command. It
-/// searches from RootPosition and at the end prints the "bestmove" to output.
+/// searches from RootPos and at the end prints the "bestmove" to output.
 
 void Search::think() {
 
   static PolyglotBook book; // Defined static to initialize the PRNG only once
 
-  Position& pos = RootPosition;
-  Chess960 = pos.is_chess960();
-  Eval::RootColor = pos.side_to_move();
-  TimeMgr.init(Limits, pos.startpos_ply_counter(), pos.side_to_move());
-  TT.new_search();
-  H.clear();
+  RootColor = RootPos.side_to_move();
+  TimeMgr.init(Limits, RootPos.startpos_ply_counter(), RootColor);
 
   if (RootMoves.empty())
   {
+      RootMoves.push_back(MOVE_NONE);
       sync_cout << "info depth 0 score "
-                << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW) << sync_endl;
+                << score_to_uci(RootPos.in_check() ? -VALUE_MATE : VALUE_DRAW)
+                << sync_endl;
 
-      RootMoves.push_back(MOVE_NONE);
       goto finalize;
   }
 
   if (Options["OwnBook"] && !Limits.infinite)
   {
-      Move bookMove = book.probe(pos, Options["Book File"], Options["Best Book Move"]);
+      Move bookMove = book.probe(RootPos, Options["Book File"], Options["Best Book Move"]);
 
       if (bookMove && std::count(RootMoves.begin(), RootMoves.end(), bookMove))
       {
@@ -253,22 +209,24 @@ void Search::think() {
       }
   }
 
-  UCIMultiPV = Options["MultiPV"];
-  SkillLevel = Options["Skill Level"];
-
-  // Do we have to play with skill handicap? In this case enable MultiPV that
-  // we will use behind the scenes to retrieve a set of possible moves.
-  SkillLevelEnabled = (SkillLevel < 20);
-  MultiPV = (SkillLevelEnabled ? std::max(UCIMultiPV, (size_t)4) : UCIMultiPV);
+  if (Options["Contempt Factor"] && !Options["UCI_AnalyseMode"])
+  {
+      int cf = Options["Contempt Factor"] * PawnValueMg / 100; // From centipawns
+      cf = cf * MaterialTable::game_phase(RootPos) / PHASE_MIDGAME; // Scale down with phase
+      DrawValue[ RootColor] = VALUE_DRAW - Value(cf);
+      DrawValue[~RootColor] = VALUE_DRAW + Value(cf);
+  }
+  else
+      DrawValue[WHITE] = DrawValue[BLACK] = VALUE_DRAW;
 
   if (Options["Use Search Log"])
   {
       Log log(Options["Search Log Filename"]);
-      log << "\nSearching: "  << pos.to_fen()
+      log << "\nSearching: "  << RootPos.to_fen()
           << "\ninfinite: "   << Limits.infinite
           << " ponder: "      << Limits.ponder
-          << " time: "        << Limits.time[pos.side_to_move()]
-          << " increment: "   << Limits.inc[pos.side_to_move()]
+          << " time: "        << Limits.time[RootColor]
+          << " increment: "   << Limits.inc[RootColor]
           << " moves to go: " << Limits.movestogo
           << std::endl;
   }
@@ -278,14 +236,14 @@ void Search::think() {
   // Set best timer interval to avoid lagging under time pressure. Timer is
   // used to check for remaining available thinking time.
   if (Limits.use_time_management())
-      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 16, TimerResolution)));
+      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 16,
+                                               TimerResolution)));
   else if (Limits.nodes)
       Threads.set_timer(2 * TimerResolution);
   else
       Threads.set_timer(100);
 
-  // We're ready to start searching. Call the iterative deepening loop function
-  id_loop(pos);
+  id_loop(RootPos); // Let's start searching !
 
   Threads.set_timer(0); // Stop timer
   Threads.sleep();
@@ -295,14 +253,14 @@ void Search::think() {
       Time::point elapsed = Time::now() - SearchTime + 1;
 
       Log log(Options["Search Log Filename"]);
-      log << "Nodes: "          << pos.nodes_searched()
-          << "\nNodes/second: " << pos.nodes_searched() * 1000 / elapsed
-          << "\nBest move: "    << move_to_san(pos, RootMoves[0].pv[0]);
+      log << "Nodes: "          << RootPos.nodes_searched()
+          << "\nNodes/second: " << RootPos.nodes_searched() * 1000 / elapsed
+          << "\nBest move: "    << move_to_san(RootPos, RootMoves[0].pv[0]);
 
       StateInfo st;
-      pos.do_move(RootMoves[0].pv[0], st);
-      log << "\nPonder move: " << move_to_san(pos, RootMoves[0].pv[1]) << std::endl;
-      pos.undo_move(RootMoves[0].pv[0]);
+      RootPos.do_move(RootMoves[0].pv[0], st);
+      log << "\nPonder move: " << move_to_san(RootPos, RootMoves[0].pv[1]) << std::endl;
+      RootPos.undo_move(RootMoves[0].pv[0]);
   }
 
 finalize:
@@ -311,11 +269,12 @@ finalize:
   // 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))
-      pos.this_thread()->wait_for_stop_or_ponderhit();
+      RootPos.this_thread()->wait_for_stop_or_ponderhit();
 
   // Best move could be MOVE_NONE when searching on a stalemate position
-  sync_cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960)
-            << " ponder "  << move_to_uci(RootMoves[0].pv[1], Chess960) << sync_endl;
+  sync_cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], RootPos.is_chess960())
+            << " ponder "  << move_to_uci(RootMoves[0].pv[1], RootPos.is_chess960())
+            << sync_endl;
 }
 
 
@@ -331,26 +290,37 @@ namespace {
     int depth, prevBestMoveChanges;
     Value bestValue, alpha, beta, delta;
     bool bestMoveNeverChanged = true;
-    Move skillBest = MOVE_NONE;
 
     memset(ss, 0, 4 * sizeof(Stack));
     depth = BestMoveChanges = 0;
     bestValue = delta = -VALUE_INFINITE;
     ss->currentMove = MOVE_NULL; // Hack to skip update gains
+    TT.new_search();
+    H.clear();
+
+    PVSize = Options["MultiPV"];
+    Skill skill(Options["Skill Level"]);
+
+    // Do we have to play with skill handicap? In this case enable MultiPV search
+    // that we will use behind the scenes to retrieve a set of possible moves.
+    if (skill.enabled() && PVSize < 4)
+        PVSize = 4;
+
+    PVSize = std::min(PVSize, RootMoves.size());
 
     // Iterative deepening loop until requested to stop or target depth reached
-    while (!Signals.stop && ++depth <= MAX_PLY && (!Limits.depth || depth <= Limits.depth))
+    while (++depth <= MAX_PLY && !Signals.stop && (!Limits.depth || depth <= Limits.depth))
     {
         // 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;
+        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 < std::min(MultiPV, RootMoves.size()); PVIdx++)
+        for (PVIdx = 0; PVIdx < PVSize; PVIdx++)
         {
             // Set aspiration window default width
             if (depth >= 5 && abs(RootMoves[PVIdx].prevScore) < VALUE_KNOWN_WIN)
@@ -381,37 +351,37 @@ namespace {
                 // the already searched PV lines are preserved.
                 sort<RootMove>(RootMoves.begin() + PVIdx, RootMoves.end());
 
-                // In case we have found an exact score and we are going to leave
-                // the fail high/low loop then reorder the PV moves, otherwise
-                // leave the last PV move in its position so to be searched again.
-                // Of course this is needed only in MultiPV search.
-                if (PVIdx && bestValue > alpha && bestValue < beta)
-                    sort<RootMove>(RootMoves.begin(), RootMoves.begin() + PVIdx);
-
                 // Write PV back to transposition table in case the relevant
                 // entries have been overwritten during the search.
                 for (size_t i = 0; i <= PVIdx; i++)
                     RootMoves[i].insert_pv_in_tt(pos);
 
-                // If search has been stopped exit the aspiration window loop.
-                // Sorting and writing PV back to TT is safe becuase RootMoves
-                // is still valid, although refers to previous iteration.
+                // If search has been stopped return immediately. Sorting and
+                // writing PV back to TT is safe becuase RootMoves is still
+                // valid, although refers to previous iteration.
                 if (Signals.stop)
+                    return;
+
+                // In case of failing high/low increase aspiration window and
+                // research, otherwise exit the loop.
+                if (bestValue > alpha && bestValue < beta)
                     break;
 
-                // Send full PV info to GUI if we are going to leave the loop or
-                // if we have a fail high/low and we are deep in the search.
-                if ((bestValue > alpha && bestValue < beta) || Time::now() - SearchTime > 2000)
+                // Give some update (without cluttering the UI) before to research
+                if (Time::now() - SearchTime > 3000)
                     sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
 
-                // In case of failing high/low increase aspiration window and
-                // research, otherwise exit the fail high/low loop.
-                if (bestValue >= beta)
+                if (abs(bestValue) >= VALUE_KNOWN_WIN)
+                {
+                    alpha = -VALUE_INFINITE;
+                    beta  =  VALUE_INFINITE;
+                }
+                else if (bestValue >= beta)
                 {
                     beta += delta;
                     delta += delta / 2;
                 }
-                else if (bestValue <= alpha)
+                else
                 {
                     Signals.failedLowAtRoot = true;
                     Signals.stopOnPonderhit = false;
@@ -419,25 +389,20 @@ namespace {
                     alpha -= delta;
                     delta += delta / 2;
                 }
-                else
-                    break;
-
-                // Search with full window in case we have a win/mate score
-                if (abs(bestValue) >= VALUE_KNOWN_WIN)
-                {
-                    alpha = -VALUE_INFINITE;
-                    beta  =  VALUE_INFINITE;
-                }
 
                 assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
             }
+
+            // Sort the PV lines searched so far and update the GUI
+            sort<RootMove>(RootMoves.begin(), RootMoves.begin() + PVIdx);
+            sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
         }
 
-        // Skills: Do we need to pick now the best move ?
-        if (SkillLevelEnabled && depth == 1 + SkillLevel)
-            skillBest = do_skill_level();
+        // Do we need to pick now the sub-optimal best move ?
+        if (skill.enabled() && skill.time_to_pick(depth))
+            skill.pick_move();
 
-        if (!Signals.stop && Options["Use Search Log"])
+        if (Options["Use Search Log"])
         {
             Log log(Options["Search Log Filename"]);
             log << pretty_pv(pos, depth, bestValue, Time::now() - SearchTime, &RootMoves[0].pv[0])
@@ -449,12 +414,12 @@ namespace {
             bestMoveNeverChanged = false;
 
         // Do we have time for the next iteration? Can we stop searching now?
-        if (!Signals.stop && !Signals.stopOnPonderhit && Limits.use_time_management())
+        if (Limits.use_time_management() && !Signals.stopOnPonderhit)
         {
             bool stop = false; // Local variable, not the volatile Signals.stop
 
             // Take in account some extra time if the best move has changed
-            if (depth > 4 && depth < 50)
+            if (depth > 4 && depth < 50 &&  PVSize == 1)
                 TimeMgr.pv_instability(BestMoveChanges, prevBestMoveChanges);
 
             // Stop search if most of available time is already consumed. We
@@ -466,10 +431,11 @@ namespace {
             // Stop search early if one move seems to be much better than others
             if (    depth >= 12
                 && !stop
+                &&  PVSize == 1
                 && (   (bestMoveNeverChanged &&  pos.captured_piece_type())
                     || Time::now() - SearchTime > (TimeMgr.available_time() * 40) / 100))
             {
-                Value rBeta = bestValue - EasyMoveMargin;
+                Value rBeta = bestValue - 2 * PawnValueMg;
                 (ss+1)->excludedMove = RootMoves[0].pv[0];
                 (ss+1)->skipNullMove = true;
                 Value v = search<NonPV>(pos, ss+1, rBeta - 1, rBeta, (depth - 3) * ONE_PLY);
@@ -491,15 +457,6 @@ namespace {
             }
         }
     }
-
-    // When using skills swap best PV line with the sub-optimal one
-    if (SkillLevelEnabled)
-    {
-        if (skillBest == MOVE_NONE) // Still unassigned ?
-            skillBest = do_skill_level();
-
-        std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), skillBest));
-    }
   }
 
 
@@ -528,16 +485,15 @@ namespace {
     Key posKey;
     Move ttMove, move, excludedMove, bestMove, threatMove;
     Depth ext, newDepth;
-    Value bestValue, value, oldAlpha, ttValue;
-    Value refinedValue, nullValue, futilityValue;
-    bool pvMove, inCheck, singularExtensionNode, givesCheck;
+    Value bestValue, value, ttValue;
+    Value eval, nullValue, futilityValue;
+    bool inCheck, givesCheck, pvMove, singularExtensionNode;
     bool captureOrPromotion, dangerous, doFullDepthSearch;
     int moveCount, playedMoveCount;
 
     // Step 1. Initialize node
     Thread* thisThread = pos.this_thread();
     moveCount = playedMoveCount = 0;
-    oldAlpha = alpha;
     inCheck = pos.in_check();
 
     if (SpNode)
@@ -568,8 +524,8 @@ namespace {
     if (!RootNode)
     {
         // Step 2. Check for aborted search and immediate draw
-        if (Signals.stop || pos.is_draw<false>() || ss->ply > MAX_PLY)
-            return VALUE_DRAW;
+        if (Signals.stop || pos.is_draw<true, PvNode>() || 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
         // would be at best mate_in(ss->ply+1), but if alpha is already bigger because
@@ -596,8 +552,13 @@ namespace {
     // a fail high/low. Biggest advantage at probing at PV nodes is to have a
     // smooth experience in analysis mode. We don't probe at Root nodes otherwise
     // we should also update RootMoveList to avoid bogus output.
-    if (!RootNode && tte && (PvNode ? tte->depth() >= depth && tte->type() == BOUND_EXACT
-                                    : can_return_tt(tte, depth, ttValue, beta)))
+    if (   !RootNode
+        && tte
+        && tte->depth() >= depth
+        && ttValue != VALUE_NONE // Only in case of TT access race
+        && (           PvNode ?  tte->type() == BOUND_EXACT
+            : ttValue >= beta ? (tte->type() & BOUND_LOWER)
+                              : (tte->type() & BOUND_UPPER)))
     {
         TT.refresh(tte);
         ss->currentMove = ttMove; // Can be MOVE_NONE
@@ -615,38 +576,51 @@ namespace {
 
     // Step 5. Evaluate the position statically and update parent's gain statistics
     if (inCheck)
-        ss->eval = ss->evalMargin = refinedValue = VALUE_NONE;
+        ss->staticEval = ss->evalMargin = eval = VALUE_NONE;
+
     else if (tte)
     {
-        assert(tte->static_value() != VALUE_NONE);
+        // Following asserts are valid only in single thread condition because
+        // TT access is always racy and its contents cannot be trusted.
+        assert(tte->static_value() != VALUE_NONE || Threads.size() > 1);
+        assert(ttValue != VALUE_NONE || tte->type() == BOUND_NONE || Threads.size() > 1);
 
-        ss->eval = tte->static_value();
+        ss->staticEval = eval = tte->static_value();
         ss->evalMargin = tte->static_value_margin();
-        refinedValue = refine_eval(tte, ttValue, ss->eval);
+
+        if (eval == VALUE_NONE || ss->evalMargin == VALUE_NONE) // Due to a race
+            eval = ss->staticEval = evaluate(pos, ss->evalMargin);
+
+        // Can ttValue be used as a better position evaluation?
+        if (ttValue != VALUE_NONE)
+            if (   ((tte->type() & BOUND_LOWER) && ttValue > eval)
+                || ((tte->type() & BOUND_UPPER) && ttValue < eval))
+                eval = ttValue;
     }
     else
     {
-        refinedValue = ss->eval = evaluate(pos, ss->evalMargin);
-        TT.store(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE, ss->eval, ss->evalMargin);
+        eval = ss->staticEval = evaluate(pos, ss->evalMargin);
+        TT.store(posKey, VALUE_NONE, BOUND_NONE, DEPTH_NONE, MOVE_NONE,
+                 ss->staticEval, ss->evalMargin);
     }
 
     // Update gain for the parent non-capture move given the static position
     // evaluation before and after the move.
-    if (    (move = (ss-1)->currentMove) != MOVE_NULL
-        &&  (ss-1)->eval != VALUE_NONE
-        &&  ss->eval != VALUE_NONE
+    if (   (move = (ss-1)->currentMove) != MOVE_NULL
+        && (ss-1)->staticEval != VALUE_NONE
+        &&  ss->staticEval != VALUE_NONE
         && !pos.captured_piece_type()
         &&  type_of(move) == NORMAL)
     {
         Square to = to_sq(move);
-        H.update_gain(pos.piece_on(to), to, -(ss-1)->eval - ss->eval);
+        H.update_gain(pos.piece_on(to), to, -(ss-1)->staticEval - ss->staticEval);
     }
 
     // Step 6. Razoring (is omitted in PV nodes)
     if (   !PvNode
-        &&  depth < RazorDepth
+        &&  depth < 4 * ONE_PLY
         && !inCheck
-        &&  refinedValue + razor_margin(depth) < beta
+        &&  eval + razor_margin(depth) < beta
         &&  ttMove == MOVE_NONE
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
         && !pos.pawn_on_7th(pos.side_to_move()))
@@ -664,19 +638,19 @@ namespace {
     // the score by more than futility_margin(depth) if we do a null move.
     if (   !PvNode
         && !ss->skipNullMove
-        &&  depth < RazorDepth
+        &&  depth < 4 * ONE_PLY
         && !inCheck
-        &&  refinedValue - futility_margin(depth, 0) >= beta
+        &&  eval - FutilityMargins[depth][0] >= beta
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
         &&  pos.non_pawn_material(pos.side_to_move()))
-        return refinedValue - futility_margin(depth, 0);
+        return eval - FutilityMargins[depth][0];
 
     // Step 8. Null move search with verification search (is omitted in PV nodes)
     if (   !PvNode
         && !ss->skipNullMove
         &&  depth > ONE_PLY
         && !inCheck
-        &&  refinedValue >= beta
+        &&  eval >= beta
         &&  abs(beta) < VALUE_MATE_IN_MAX_PLY
         &&  pos.non_pawn_material(pos.side_to_move()))
     {
@@ -686,7 +660,7 @@ namespace {
         Depth R = 3 * ONE_PLY + depth / 4;
 
         // Null move dynamic reduction based on value
-        if (refinedValue - PawnValueMg > beta)
+        if (eval - PawnValueMg > beta)
             R += ONE_PLY;
 
         pos.do_null_move<true>(st);
@@ -723,7 +697,7 @@ namespace {
             // parent node, which will trigger a re-search with full depth).
             threatMove = (ss+1)->currentMove;
 
-            if (   depth < ThreatDepth
+            if (   depth < 5 * ONE_PLY
                 && (ss-1)->reduction
                 && threatMove != MOVE_NONE
                 && connected_moves(pos, (ss-1)->currentMove, threatMove))
@@ -736,7 +710,7 @@ namespace {
     // and a reduced search returns a value much above beta, we can (almost) safely
     // prune the previous move.
     if (   !PvNode
-        &&  depth >= RazorDepth + ONE_PLY
+        &&  depth >= 5 * ONE_PLY
         && !inCheck
         && !ss->skipNullMove
         &&  excludedMove == MOVE_NONE
@@ -765,9 +739,9 @@ namespace {
     }
 
     // Step 10. Internal iterative deepening
-    if (   depth >= IIDDepth[PvNode]
+    if (   depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY)
         && ttMove == MOVE_NONE
-        && (PvNode || (!inCheck && ss->eval + IIDMargin >= beta)))
+        && (PvNode || (!inCheck && ss->staticEval + Value(256) >= beta)))
     {
         Depth d = (PvNode ? depth - 2 * ONE_PLY : depth / 2);
 
@@ -786,7 +760,7 @@ split_point_start: // At split points actual search starts from here
     value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
     singularExtensionNode =   !RootNode
                            && !SpNode
-                           &&  depth >= SingularExtensionDepth[PvNode]
+                           &&  depth >= (PvNode ? 6 * ONE_PLY : 8 * ONE_PLY)
                            &&  ttMove != MOVE_NONE
                            && !excludedMove // Recursive singular search is not allowed
                            && (tte->type() & BOUND_LOWER)
@@ -794,10 +768,7 @@ split_point_start: // At split points actual search starts from here
 
     // 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<SpNode>()) != MOVE_NONE
-           && !thisThread->cutoff_occurred()
-           && !Signals.stop)
+    while ((move = mp.next_move<SpNode>()) != MOVE_NONE)
     {
       assert(is_ok(move));
 
@@ -828,14 +799,21 @@ split_point_start: // At split points actual search starts from here
 
           if (thisThread == Threads.main_thread() && Time::now() - SearchTime > 2000)
               sync_cout << "info depth " << depth / ONE_PLY
-                        << " currmove " << move_to_uci(move, Chess960)
+                        << " currmove " << move_to_uci(move, pos.is_chess960())
                         << " currmovenumber " << moveCount + PVIdx << sync_endl;
       }
 
+      ext = DEPTH_ZERO;
       captureOrPromotion = pos.is_capture_or_promotion(move);
       givesCheck = pos.move_gives_check(move, ci);
-      dangerous = givesCheck || is_dangerous(pos, move, captureOrPromotion);
-      ext = DEPTH_ZERO;
+      dangerous =   givesCheck
+                 || pos.is_passed_pawn_push(move)
+                 || type_of(move) == CASTLE
+                 || (   captureOrPromotion // Entering a pawn endgame?
+                     && type_of(pos.piece_on(to_sq(move))) != PAWN
+                     && type_of(move) == NORMAL
+                     && (  pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
+                         - PieceValue[MG][pos.piece_on(to_sq(move))] == VALUE_ZERO));
 
       // Step 12. Extend checks and, in PV nodes, also dangerous moves
       if (PvNode && dangerous)
@@ -850,11 +828,13 @@ split_point_start: // At split points actual search starts from here
       // on all the other moves but the ttMove, if result is lower than ttValue minus
       // a margin then we extend ttMove.
       if (    singularExtensionNode
-          && !ext
           &&  move == ttMove
+          && !ext
           &&  pos.pl_move_is_legal(move, ci.pinned)
           &&  abs(ttValue) < VALUE_KNOWN_WIN)
       {
+          assert(ttValue != VALUE_NONE);
+
           Value rBeta = ttValue - int(depth);
           ss->excludedMove = move;
           ss->skipNullMove = true;
@@ -875,10 +855,12 @@ split_point_start: // At split points actual search starts from here
           && !inCheck
           && !dangerous
           &&  move != ttMove
-          && (bestValue > VALUE_MATED_IN_MAX_PLY || bestValue == -VALUE_INFINITE))
+          && (bestValue > VALUE_MATED_IN_MAX_PLY || (   bestValue == -VALUE_INFINITE
+                                                     && alpha > VALUE_MATED_IN_MAX_PLY)))
       {
           // Move count based pruning
-          if (   moveCount >= futility_move_count(depth)
+          if (   depth < 16 * ONE_PLY
+              && moveCount >= FutilityMoveCounts[depth]
               && (!threatMove || !connected_threat(pos, move, threatMove)))
           {
               if (SpNode)
@@ -891,7 +873,7 @@ split_point_start: // At split points actual search starts from here
           // We illogically ignore reduction condition depth >= 3*ONE_PLY for predicted depth,
           // but fixing this made program slightly weaker.
           Depth predictedDepth = newDepth - reduction<PvNode>(depth, moveCount);
-          futilityValue =  ss->eval + ss->evalMargin + futility_margin(predictedDepth, moveCount)
+          futilityValue =  ss->staticEval + ss->evalMargin + futility_margin(predictedDepth, moveCount)
                          + H.gain(pos.piece_moved(move), to_sq(move));
 
           if (futilityValue < beta)
@@ -981,7 +963,10 @@ split_point_start: // At split points actual search starts from here
       // 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 (RootNode && !Signals.stop)
+      if (Signals.stop || thisThread->cutoff_occurred())
+          return value; // To avoid returning VALUE_INFINITE
+
+      if (RootNode)
       {
           RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move);
 
@@ -994,7 +979,7 @@ split_point_start: // At split points actual search starts from here
               // We record how often the best move has been changed in each
               // iteration. This information is used for time management: When
               // the best move changes frequently, we allocate some more time.
-              if (!pvMove && MultiPV == 1)
+              if (!pvMove)
                   BestMoveChanges++;
           }
           else
@@ -1007,37 +992,41 @@ split_point_start: // At split points actual search starts from here
       if (value > bestValue)
       {
           bestValue = value;
-          bestMove = move;
+          if (SpNode) sp->bestValue = value;
 
-          if (   PvNode
-              && value > alpha
-              && value < beta) // We want always alpha < beta
+          if (value > alpha)
           {
-              alpha = bestValue; // Update alpha here!
-          }
-
-          if (SpNode && !thisThread->cutoff_occurred())
-          {
-              sp->bestValue = bestValue;
-              sp->bestMove = bestMove;
-              sp->alpha = alpha;
+              bestMove = move;
+              if (SpNode) sp->bestMove = move;
 
-              if (bestValue >= beta)
-                  sp->cutoff = true;
+              if (PvNode && value < beta)
+              {
+                  alpha = value; // Update alpha here! Always alpha < beta
+                  if (SpNode) sp->alpha = value;
+              }
+              else // Fail high
+              {
+                  if (SpNode) sp->cutoff = true;
+                  break;
+              }
           }
       }
 
-      // Step 19. Check for split
+      // Step 19. Check for splitting the search
       if (   !SpNode
           &&  depth >= Threads.min_split_depth()
           &&  bestValue < beta
-          &&  Threads.available_slave_exists(thisThread)
-          && !Signals.stop
-          && !thisThread->cutoff_occurred())
+          &&  Threads.available_slave_exists(thisThread))
+      {
           bestValue = Threads.split<FakeSplit>(pos, ss, alpha, beta, bestValue, &bestMove,
                                                depth, threatMove, moveCount, mp, NT);
+          break;
+      }
     }
 
+    if (SpNode)
+        return bestValue;
+
     // 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
@@ -1045,8 +1034,9 @@ split_point_start: // At split points actual search starts from here
     // 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.
     // A split node has at least one move, the one tried before to be splitted.
-    if (!SpNode && !moveCount)
-        return excludedMove ? alpha : inCheck ? mated_in(ss->ply) : VALUE_DRAW;
+    if (!moveCount)
+        return  excludedMove ? alpha
+              : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()];
 
     // If we have pruned all the moves without searching return a fail-low score
     if (bestValue == -VALUE_INFINITE)
@@ -1056,20 +1046,12 @@ split_point_start: // At split points actual search starts from here
         bestValue = alpha;
     }
 
-    // Step 21. Update tables
-    // Update transposition table entry, killers and history
-    if (!SpNode && !Signals.stop && !thisThread->cutoff_occurred())
+    if (bestValue >= beta) // Failed high
     {
-        Move ttm = bestValue <= oldAlpha ? MOVE_NONE : bestMove;
-        Bound bt = bestValue <= oldAlpha ? BOUND_UPPER
-                 : bestValue >= beta ? BOUND_LOWER : BOUND_EXACT;
+        TT.store(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, depth,
+                 bestMove, ss->staticEval, ss->evalMargin);
 
-        TT.store(posKey, value_to_tt(bestValue, ss->ply), bt, depth, ttm, ss->eval, ss->evalMargin);
-
-        // Update killers and history for non capture cut-off moves
-        if (    bestValue >= beta
-            && !pos.is_capture_or_promotion(bestMove)
-            && !inCheck)
+        if (!pos.is_capture_or_promotion(bestMove) && !inCheck)
         {
             if (bestMove != ss->killers[0])
             {
@@ -1089,6 +1071,10 @@ split_point_start: // At split points actual search starts from here
             }
         }
     }
+    else // Failed low or PV search
+        TT.store(posKey, value_to_tt(bestValue, ss->ply),
+                 PvNode && bestMove != MOVE_NONE ? BOUND_EXACT : BOUND_UPPER,
+                 depth, bestMove, ss->staticEval, ss->evalMargin);
 
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
@@ -1107,38 +1093,43 @@ 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((alpha == beta - 1) || PvNode);
+    assert(PvNode || (alpha == beta - 1));
     assert(depth <= DEPTH_ZERO);
 
     StateInfo st;
-    Move ttMove, move, bestMove;
-    Value ttValue, bestValue, value, evalMargin, futilityValue, futilityBase;
-    bool inCheck, enoughMaterial, givesCheck, evasionPrunable;
     const TTEntry* tte;
+    Key posKey;
+    Move ttMove, move, bestMove;
+    Value bestValue, value, ttValue, futilityValue, futilityBase;
+    bool inCheck, givesCheck, enoughMaterial, evasionPrunable;
     Depth ttDepth;
-    Bound bt;
-    Value oldAlpha = alpha;
 
+    inCheck = pos.in_check();
     ss->currentMove = bestMove = MOVE_NONE;
     ss->ply = (ss-1)->ply + 1;
 
     // Check for an instant draw or maximum ply reached
-    if (pos.is_draw<true>() || ss->ply > MAX_PLY)
-        return VALUE_DRAW;
-
-    // Decide whether or not to include checks, this fixes also the type of
-    // TT entry depth that we are going to use. Note that in qsearch we use
-    // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
-    inCheck = pos.in_check();
-    ttDepth = (inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS);
+    if (pos.is_draw<false, false>() || ss->ply > MAX_PLY)
+        return DrawValue[pos.side_to_move()];
 
     // Transposition table lookup. At PV nodes, we don't use the TT for
     // pruning, but only for move ordering.
-    tte = TT.probe(pos.key());
-    ttMove = (tte ? tte->move() : MOVE_NONE);
-    ttValue = tte ? value_from_tt(tte->value(),ss->ply) : VALUE_ZERO;
+    posKey = pos.key();
+    tte = TT.probe(posKey);
+    ttMove = tte ? tte->move() : MOVE_NONE;
+    ttValue = tte ? value_from_tt(tte->value(),ss->ply) : VALUE_NONE;
 
-    if (!PvNode && tte && can_return_tt(tte, ttDepth, ttValue, beta))
+    // Decide whether or not to include checks, this fixes also the type of
+    // TT entry depth that we are going to use. Note that in qsearch we use
+    // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
+    ttDepth = inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
+                                                  : DEPTH_QS_NO_CHECKS;
+    if (   tte
+        && tte->depth() >= ttDepth
+        && ttValue != VALUE_NONE // Only in case of TT access race
+        && (           PvNode ?  tte->type() == BOUND_EXACT
+            : ttValue >= beta ? (tte->type() & BOUND_LOWER)
+                              : (tte->type() & BOUND_UPPER)))
     {
         ss->currentMove = ttMove; // Can be MOVE_NONE
         return ttValue;
@@ -1147,27 +1138,31 @@ split_point_start: // At split points actual search starts from here
     // Evaluate the position statically
     if (inCheck)
     {
+        ss->staticEval = ss->evalMargin = VALUE_NONE;
         bestValue = futilityBase = -VALUE_INFINITE;
-        ss->eval = evalMargin = VALUE_NONE;
         enoughMaterial = false;
     }
     else
     {
         if (tte)
         {
-            assert(tte->static_value() != VALUE_NONE);
+            assert(tte->static_value() != VALUE_NONE || Threads.size() > 1);
+
+            ss->staticEval = bestValue = tte->static_value();
+            ss->evalMargin = tte->static_value_margin();
 
-            evalMargin = tte->static_value_margin();
-            ss->eval = bestValue = tte->static_value();
+            if (ss->staticEval == VALUE_NONE || ss->evalMargin == VALUE_NONE) // Due to a race
+                ss->staticEval = bestValue = evaluate(pos, ss->evalMargin);
         }
         else
-            ss->eval = bestValue = evaluate(pos, evalMargin);
+            ss->staticEval = bestValue = evaluate(pos, ss->evalMargin);
 
         // Stand pat. Return immediately if static value is at least beta
         if (bestValue >= beta)
         {
             if (!tte)
-                TT.store(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin);
+                TT.store(pos.key(), value_to_tt(bestValue, ss->ply), BOUND_LOWER,
+                         DEPTH_NONE, MOVE_NONE, ss->staticEval, ss->evalMargin);
 
             return bestValue;
         }
@@ -1175,7 +1170,7 @@ split_point_start: // At split points actual search starts from here
         if (PvNode && bestValue > alpha)
             alpha = bestValue;
 
-        futilityBase = ss->eval + evalMargin + FutilityMarginQS;
+        futilityBase = ss->staticEval + ss->evalMargin + Value(128);
         enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMg;
     }
 
@@ -1187,8 +1182,7 @@ split_point_start: // At split points actual search starts from here
     CheckInfo ci(pos);
 
     // Loop through the moves until no moves remain or a beta cutoff occurs
-    while (   bestValue < beta
-           && (move = mp.next_move<false>()) != MOVE_NONE)
+    while ((move = mp.next_move<false>()) != MOVE_NONE)
     {
       assert(is_ok(move));
 
@@ -1204,7 +1198,7 @@ split_point_start: // At split points actual search starts from here
           && !pos.is_passed_pawn_push(move))
       {
           futilityValue =  futilityBase
-                         + PieceValue[Eg][pos.piece_on(to_sq(move))]
+                         + PieceValue[EG][pos.piece_on(to_sq(move))]
                          + (type_of(move) == ENPASSANT ? PawnValueEg : VALUE_ZERO);
 
           if (futilityValue < beta)
@@ -1243,7 +1237,7 @@ split_point_start: // At split points actual search starts from here
           &&  givesCheck
           &&  move != ttMove
           && !pos.is_capture_or_promotion(move)
-          &&  ss->eval + PawnValueMg / 4 < beta
+          &&  ss->staticEval + PawnValueMg / 4 < beta
           && !check_is_dangerous(pos, move, futilityBase, beta))
           continue;
 
@@ -1255,21 +1249,31 @@ split_point_start: // At split points actual search starts from here
 
       // Make and search the move
       pos.do_move(move, st, ci, givesCheck);
-      value = -qsearch<NT>(pos, ss+1, -beta, -alpha, depth-ONE_PLY);
+      value = -qsearch<NT>(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
       pos.undo_move(move);
 
       assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
 
-      // New best move?
+      // Check for new best move
       if (value > bestValue)
       {
           bestValue = value;
-          bestMove = move;
 
-          if (   PvNode
-              && value > alpha
-              && value < beta) // We want always alpha < beta
-              alpha = value;
+          if (value > alpha)
+          {
+              if (PvNode && value < beta) // Update alpha here! Always alpha < beta
+              {
+                  alpha = value;
+                  bestMove = move;
+              }
+              else // Fail high
+              {
+                  TT.store(posKey, value_to_tt(value, ss->ply), BOUND_LOWER,
+                           ttDepth, move, ss->staticEval, ss->evalMargin);
+
+                  return value;
+              }
+          }
        }
     }
 
@@ -1278,12 +1282,9 @@ split_point_start: // At split points actual search starts from here
     if (inCheck && bestValue == -VALUE_INFINITE)
         return mated_in(ss->ply); // Plies to mate from the root
 
-    // Update transposition table
-    move = bestValue <= oldAlpha ? MOVE_NONE : bestMove;
-    bt   = bestValue <= oldAlpha ? BOUND_UPPER
-         : bestValue >= beta ? BOUND_LOWER : BOUND_EXACT;
-
-    TT.store(pos.key(), value_to_tt(bestValue, ss->ply), bt, ttDepth, move, ss->eval, evalMargin);
+    TT.store(posKey, value_to_tt(bestValue, ss->ply),
+             PvNode && bestMove != MOVE_NONE ? BOUND_EXACT : BOUND_UPPER,
+             ttDepth, bestMove, ss->staticEval, ss->evalMargin);
 
     assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
 
@@ -1291,44 +1292,60 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // check_is_dangerous() tests if a checking move can be pruned in qsearch().
-  // bestValue is updated only when returning false because in that case move
-  // will be pruned.
+  // value_to_tt() adjusts a mate score from "plies to mate from the root" to
+  // "plies to mate from the current position". Non-mate scores are unchanged.
+  // The function is called before storing a value to the transposition table.
+
+  Value value_to_tt(Value v, int ply) {
 
-  bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta)
+    assert(v != VALUE_NONE);
+
+    return  v >= VALUE_MATE_IN_MAX_PLY  ? v + ply
+          : v <= VALUE_MATED_IN_MAX_PLY ? v - ply : v;
+  }
+
+
+  // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score
+  // from the transposition table (where refers to the plies to mate/be mated
+  // from current position) to "plies to mate/be mated from the root".
+
+  Value value_from_tt(Value v, int ply) {
+
+    return  v == VALUE_NONE             ? VALUE_NONE
+          : v >= VALUE_MATE_IN_MAX_PLY  ? v - ply
+          : v <= VALUE_MATED_IN_MAX_PLY ? v + ply : v;
+  }
+
+
+  // check_is_dangerous() tests if a checking move can be pruned in qsearch()
+
+  bool check_is_dangerous(Position& pos, Move move, Value futilityBase, Value beta)
   {
-    Bitboard b, occ, oldAtt, newAtt, kingAtt;
-    Square from, to, ksq;
-    Piece pc;
-    Color them;
-
-    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_moved(move);
-
-    occ = pos.pieces() ^ from ^ ksq;
-    oldAtt = pos.attacks_from(pc, from, occ);
-    newAtt = pos.attacks_from(pc,   to, occ);
-
-    // Rule 1. Checks which give opponent's king at most one escape square are dangerous
-    b = kingAtt & ~pos.pieces(them) & ~newAtt & ~(1ULL << to);
-
-    if (!more_than_one(b))
+    Piece pc = pos.piece_moved(move);
+    Square from = from_sq(move);
+    Square to = to_sq(move);
+    Color them = ~pos.side_to_move();
+    Square ksq = pos.king_square(them);
+    Bitboard enemies = pos.pieces(them);
+    Bitboard kingAtt = pos.attacks_from<KING>(ksq);
+    Bitboard occ = pos.pieces() ^ from ^ ksq;
+    Bitboard oldAtt = pos.attacks_from(pc, from, occ);
+    Bitboard newAtt = pos.attacks_from(pc, to, occ);
+
+    // Checks which give opponent's king at most one escape square are dangerous
+    if (!more_than_one(kingAtt & ~(enemies | newAtt | to)))
         return true;
 
-    // Rule 2. Queen contact check is very dangerous
+    // Queen contact check is very dangerous
     if (type_of(pc) == QUEEN && (kingAtt & to))
         return true;
 
-    // Rule 3. Creating new double threats with checks
-    b = pos.pieces(them) & newAtt & ~oldAtt & ~(1ULL << ksq);
+    // Creating new double threats with checks is dangerous
+    Bitboard b = (enemies ^ ksq) & newAtt & ~oldAtt;
     while (b)
     {
         // Note that here we generate illegal "double move"!
-        if (futilityBase + PieceValue[Eg][pos.piece_on(pop_lsb(&b))] >= beta)
+        if (futilityBase + PieceValue[EG][pos.piece_on(pop_lsb(&b))] >= beta)
             return true;
     }
 
@@ -1384,38 +1401,6 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // value_to_tt() adjusts a mate score from "plies to mate from the root" to
-  // "plies to mate from the current position". Non-mate scores are unchanged.
-  // The function is called before storing a value to the transposition table.
-
-  Value value_to_tt(Value v, int ply) {
-
-    if (v >= VALUE_MATE_IN_MAX_PLY)
-      return v + ply;
-
-    if (v <= VALUE_MATED_IN_MAX_PLY)
-      return v - ply;
-
-    return v;
-  }
-
-
-  // value_from_tt() is the inverse of value_to_tt(): It adjusts a mate score
-  // from the transposition table (where refers to the plies to mate/be mated
-  // from current position) to "plies to mate/be mated from the root".
-
-  Value value_from_tt(Value v, int ply) {
-
-    if (v >= VALUE_MATE_IN_MAX_PLY)
-      return v - ply;
-
-    if (v <= VALUE_MATED_IN_MAX_PLY)
-      return v + ply;
-
-    return v;
-  }
-
-
   // connected_threat() tests whether it is safe to forward prune a move or if
   // is somehow connected to the threat move returned by null search.
 
@@ -1426,12 +1411,10 @@ split_point_start: // At split points actual search starts from here
     assert(!pos.is_capture_or_promotion(m));
     assert(!pos.is_passed_pawn_push(m));
 
-    Square mfrom, mto, tfrom, tto;
-
-    mfrom = from_sq(m);
-    mto = to_sq(m);
-    tfrom = from_sq(threat);
-    tto = to_sq(threat);
+    Square mfrom = from_sq(m);
+    Square mto = to_sq(m);
+    Square tfrom = from_sq(threat);
+    Square tto = to_sq(threat);
 
     // Case 1: Don't prune moves which move the threatened piece
     if (mfrom == tto)
@@ -1439,11 +1422,26 @@ split_point_start: // At split points actual search starts from here
 
     // Case 2: If the threatened piece has value less than or equal to the
     // value of the threatening piece, don't prune moves which defend it.
-    if (   pos.is_capture(threat)
-        && (   PieceValue[Mg][pos.piece_on(tfrom)] >= PieceValue[Mg][pos.piece_on(tto)]
-            || type_of(pos.piece_on(tfrom)) == KING)
-        && pos.move_attacks_square(m, tto))
-        return true;
+    if (    pos.is_capture(threat)
+        && (   PieceValue[MG][pos.piece_on(tfrom)] >= PieceValue[MG][pos.piece_on(tto)]
+            || type_of(pos.piece_on(tfrom)) == KING))
+    {
+        // Update occupancy as if the piece is moving
+        Bitboard occ = pos.pieces() ^ mfrom ^ mto;
+        Piece piece = pos.piece_on(mfrom);
+
+        // The moved piece attacks the square 'tto' ?
+        if (pos.attacks_from(piece, mto, occ) & tto)
+            return true;
+
+        // Scan for possible X-ray attackers behind the moved piece
+        Bitboard xray =  (attacks_bb<  ROOK>(tto, occ) & pos.pieces(color_of(piece), QUEEN, ROOK))
+                       | (attacks_bb<BISHOP>(tto, occ) & pos.pieces(color_of(piece), QUEEN, BISHOP));
+
+        // Verify attackers are triggered by our move and not already existing
+        if (xray && (xray ^ (xray & pos.attacks_from<QUEEN>(tto))))
+            return true;
+    }
 
     // Case 3: If the moving piece in the threatened move is a slider, don't
     // prune safe moves which block its ray.
@@ -1456,41 +1454,10 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // can_return_tt() returns true if a transposition table score can be used to
-  // cut-off at a given point in search.
-
-  bool can_return_tt(const TTEntry* tte, Depth depth, Value v, Value beta) {
-
-    return   (   tte->depth() >= depth
-              || v >= std::max(VALUE_MATE_IN_MAX_PLY, beta)
-              || v < std::min(VALUE_MATED_IN_MAX_PLY, beta))
-
-          && (   ((tte->type() & BOUND_LOWER) && v >= beta)
-              || ((tte->type() & BOUND_UPPER) && v < beta));
-  }
-
-
-  // refine_eval() returns the transposition table score if possible, otherwise
-  // falls back on static position evaluation.
-
-  Value refine_eval(const TTEntry* tte, Value v, Value defaultEval) {
-
-      assert(tte);
-
-      if (   ((tte->type() & BOUND_LOWER) && v >= defaultEval)
-          || ((tte->type() & BOUND_UPPER) && v < defaultEval))
-          return v;
-
-      return defaultEval;
-  }
-
-
   // When playing with strength handicap choose best move among the MultiPV set
-  // using a statistical rule dependent on SkillLevel. Idea by Heinz van Saanen.
-
-  Move do_skill_level() {
+  // using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
 
-    assert(MultiPV > 1);
+  Move Skill::pick_move() {
 
     static RKISS rk;
 
@@ -1499,21 +1466,20 @@ split_point_start: // At split points actual search starts from here
         rk.rand<unsigned>();
 
     // RootMoves are already sorted by score in descending order
-    size_t size = std::min(MultiPV, RootMoves.size());
-    int variance = std::min(RootMoves[0].score - RootMoves[size - 1].score, PawnValueMg);
-    int weakness = 120 - 2 * SkillLevel;
+    int variance = std::min(RootMoves[0].score - RootMoves[PVSize - 1].score, PawnValueMg);
+    int weakness = 120 - 2 * level;
     int max_s = -VALUE_INFINITE;
-    Move best = MOVE_NONE;
+    best = MOVE_NONE;
 
     // Choose best move. For each move score we add two terms both dependent on
     // weakness, one deterministic and bigger for weaker moves, and one random,
     // then we choose the move with the resulting highest score.
-    for (size_t i = 0; i < size; i++)
+    for (size_t i = 0; i < PVSize; i++)
     {
         int s = RootMoves[i].score;
 
         // Don't allow crazy blunders even at very low skills
-        if (i > 0 && RootMoves[i-1].score > s + EasyMoveMargin)
+        if (i > 0 && RootMoves[i-1].score > s + 2 * PawnValueMg)
             break;
 
         // This is our magic formula
@@ -1538,23 +1504,24 @@ split_point_start: // At split points actual search starts from here
 
     std::stringstream s;
     Time::point elaspsed = Time::now() - SearchTime + 1;
+    size_t uciPVSize = std::min((size_t)Options["MultiPV"], RootMoves.size());
     int selDepth = 0;
 
     for (size_t i = 0; i < Threads.size(); i++)
         if (Threads[i].maxPly > selDepth)
             selDepth = Threads[i].maxPly;
 
-    for (size_t i = 0; i < std::min(UCIMultiPV, RootMoves.size()); i++)
+    for (size_t i = 0; i < uciPVSize; i++)
     {
         bool updated = (i <= PVIdx);
 
         if (depth == 1 && !updated)
             continue;
 
-        int d = (updated ? depth : depth - 1);
-        Value v = (updated ? RootMoves[i].score : RootMoves[i].prevScore);
+        int d   = updated ? depth : depth - 1;
+        Value v = updated ? RootMoves[i].score : RootMoves[i].prevScore;
 
-        if (s.rdbuf()->in_avail())
+        if (s.rdbuf()->in_avail()) // Not at first line
             s << "\n";
 
         s << "info depth " << d
@@ -1567,7 +1534,7 @@ split_point_start: // At split points actual search starts from here
           << " pv";
 
         for (size_t j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++)
-            s <<  " " << move_to_uci(RootMoves[i].pv[j], Chess960);
+            s <<  " " << move_to_uci(RootMoves[i].pv[j], pos.is_chess960());
     }
 
     return s.str();
@@ -1585,29 +1552,27 @@ void RootMove::extract_pv_from_tt(Position& pos) {
 
   StateInfo state[MAX_PLY_PLUS_2], *st = state;
   TTEntry* tte;
-  int ply = 1;
+  int ply = 0;
   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
-         && (m = tte->move()) != MOVE_NONE // Local copy, TT entry could change
-         && pos.is_pseudo_legal(m)
-         && pos.pl_move_is_legal(m, pos.pinned_pieces())
-         && ply < MAX_PLY
-         && (!pos.is_draw<false>() || ply < 2))
-  {
+
+  do {
       pv.push_back(m);
-      pos.do_move(m, *st++);
-      ply++;
-  }
-  pv.push_back(MOVE_NONE);
 
-  do pos.undo_move(pv[--ply]); while (ply);
+      assert(pos.move_is_legal(pv[ply]));
+      pos.do_move(pv[ply++], *st++);
+      tte = TT.probe(pos.key());
+
+  } while (   tte
+           && pos.is_pseudo_legal(m = tte->move()) // Local copy, TT could change
+           && pos.pl_move_is_legal(m, pos.pinned_pieces())
+           && ply < MAX_PLY
+           && (!pos.is_draw<true, true>() || ply < 2));
+
+  pv.push_back(MOVE_NONE); // Must be zero-terminating
+
+  while (ply) pos.undo_move(pv[--ply]);
 }
 
 
@@ -1619,27 +1584,28 @@ void RootMove::insert_pv_in_tt(Position& pos) {
 
   StateInfo state[MAX_PLY_PLUS_2], *st = state;
   TTEntry* tte;
-  Key k;
-  Value v, m = VALUE_NONE;
   int ply = 0;
-
-  assert(pv[ply] != MOVE_NONE && pos.is_pseudo_legal(pv[ply]));
+  Value v, m;
 
   do {
-      k = pos.key();
-      tte = TT.probe(k);
+      tte = TT.probe(pos.key());
 
-      // Don't overwrite existing correct entries
-      if (!tte || tte->move() != pv[ply])
+      if (!tte || tte->move() != pv[ply]) // Don't overwrite correct entries
       {
-          v = (pos.in_check() ? VALUE_NONE : evaluate(pos, m));
-          TT.store(k, VALUE_NONE, BOUND_NONE, DEPTH_NONE, pv[ply], v, m);
+          if (pos.in_check())
+              v = m = VALUE_NONE;
+          else
+              v = evaluate(pos, m);
+
+          TT.store(pos.key(), VALUE_NONE, BOUND_NONE, DEPTH_NONE, pv[ply], v, m);
       }
-      pos.do_move(pv[ply], *st++);
 
-  } while (pv[++ply] != MOVE_NONE);
+      assert(pos.move_is_legal(pv[ply]));
+      pos.do_move(pv[ply++], *st++);
+
+  } while (pv[ply] != MOVE_NONE);
 
-  do pos.undo_move(pv[--ply]); while (ply);
+  while (ply) pos.undo_move(pv[--ply]);
 }
 
 
@@ -1771,7 +1737,7 @@ void check_time() {
   {
       Threads.mutex.lock();
 
-      nodes = RootPosition.nodes_searched();
+      nodes = RootPos.nodes_searched();
 
       // Loop across all split points and sum accumulated SplitPoint nodes plus
       // all the currently active slaves positions.