]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Retire singleEvasion
[stockfish] / src / search.cpp
index bc0fff881ef7f003ead9e194d35ab91b887cc207..eb19b51d9c994c5d11e8c9c7abfb195806e475af 100644 (file)
@@ -129,7 +129,7 @@ namespace {
 
     void extract_pv_from_tt(Position& pos);
     void insert_pv_in_tt(Position& pos);
-    std::string pv_info_to_uci(Position& pos, Value alpha, Value beta, int pvLine = 0);
+    std::string pv_info_to_uci(Position& pos, Depth depth, Value alpha, Value beta, int pvLine = 0);
 
     int64_t nodes;
     Value pv_score;
@@ -145,11 +145,11 @@ namespace {
 
     typedef std::vector<RootMove> Base;
 
-    RootMoveList(Position& pos, Move searchMoves[]);
-    void set_non_pv_scores(const Position& pos, Move ttm, SearchStack* ss);
-
+    void init(Position& pos, Move searchMoves[]);
     void sort() { insertion_sort<RootMove, Base::iterator>(begin(), end()); }
     void sort_multipv(int n) { insertion_sort<RootMove, Base::iterator>(begin(), begin() + n); }
+
+    int bestMoveChanges;
   };
 
 
@@ -203,8 +203,8 @@ namespace {
 
   // Extensions. Configurable UCI options
   // Array index 0 is used at non-PV nodes, index 1 at PV nodes.
-  Depth CheckExtension[2], SingleEvasionExtension[2], PawnPushTo7thExtension[2];
-  Depth PassedPawnExtension[2], PawnEndgameExtension[2], MateThreatExtension[2];
+  Depth CheckExtension[2], PawnPushTo7thExtension[2], PassedPawnExtension[2];
+  Depth PawnEndgameExtension[2], MateThreatExtension[2];
 
   // Minimum depth for use of singular extension
   const Depth SingularExtensionDepth[2] = { 8 * ONE_PLY /* non-PV */, 6 * ONE_PLY /* PV */};
@@ -233,11 +233,6 @@ namespace {
   template <NodeType PV>
   inline Depth reduction(Depth d, int mn) { return (Depth) ReductionMatrix[PV][Min(d / 2, 63)][Min(mn, 63)]; }
 
-  // Common adjustments
-
-  // Search depth at iteration 1
-  const Depth InitialDepth = ONE_PLY;
-
   // Easy move margin. An easy move candidate must be at least this much
   // better than the second best move.
   const Value EasyMoveMargin = Value(0x200);
@@ -248,18 +243,8 @@ namespace {
   // Book object
   Book OpeningBook;
 
-  // Pointer to root move list
-  RootMoveList* Rml;
-
-  // Iteration counter
-  int Iteration;
-
-  // Scores and number of times the best move changed for each iteration
-  Value ValueByIteration[PLY_MAX_PLUS_2];
-  int BestMoveChangesByIteration[PLY_MAX_PLUS_2];
-
-  // Search window management
-  int AspirationDelta;
+  // Root move list
+  RootMoveList Rml;
 
   // MultiPV mode
   int MultiPV;
@@ -289,7 +274,6 @@ namespace {
   /// Local functions
 
   Move id_loop(Position& pos, Move searchMoves[], Move* ponderMove);
-  Value root_search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, RootMoveList& rml);
 
   template <NodeType PvNode, bool SpNode, bool Root>
   Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply);
@@ -305,7 +289,7 @@ namespace {
   }
 
   template <NodeType PvNode>
-  Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous);
+  Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool mateThreat, bool* dangerous);
 
   bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta, Value *bValue);
   bool connected_moves(const Position& pos, Move m1, Move m2);
@@ -318,13 +302,13 @@ namespace {
   void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount);
   void update_killers(Move m, Move killers[]);
   void update_gains(const Position& pos, Move move, Value before, Value after);
+  void qsearch_scoring(Position& pos, MoveStack* mlist, MoveStack* last);
 
   int current_search_time();
   std::string value_to_uci(Value v);
   int nps(const Position& pos);
   void poll(const Position& pos);
   void wait_for_stop_or_ponderhit();
-  void init_ss_array(SearchStack* ss, int size);
 
 #if !defined(_MSC_VER)
   void* init_thread(void* threadID);
@@ -332,7 +316,73 @@ namespace {
   DWORD WINAPI init_thread(LPVOID threadID);
 #endif
 
-}
+
+  // MovePickerExt is an extended MovePicker used to choose at compile time
+  // the proper move source according to the type of node.
+  template<bool SpNode, bool Root> struct MovePickerExt;
+
+  // In Root nodes use RootMoveList Rml as source. Score and sort the root moves
+  // before to search them.
+  template<> struct MovePickerExt<false, true> : public MovePicker {
+
+    MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)
+                 : MovePicker(p, ttm, d, h, ss, b), firstCall(true) {
+      Move move;
+      Value score = VALUE_ZERO;
+
+      // Score root moves using the standard way used in main search, the moves
+      // are scored according to the order in which are returned by MovePicker.
+      // This is the second order score that is used to compare the moves when
+      // the first order pv scores of both moves are equal.
+      while ((move = MovePicker::get_next_move()) != MOVE_NONE)
+          for (rm = Rml.begin(); rm != Rml.end(); ++rm)
+              if (rm->pv[0] == move)
+              {
+                  rm->non_pv_score = score--;
+                  break;
+              }
+
+      Rml.sort();
+      rm = Rml.begin();
+    }
+
+    Move get_next_move() {
+
+      if (!firstCall)
+          ++rm;
+      else
+          firstCall = false;
+
+      return rm != Rml.end() ? rm->pv[0] : MOVE_NONE;
+    }
+
+    RootMoveList::iterator rm;
+    bool firstCall;
+  };
+
+  // In SpNodes use split point's shared MovePicker object as move source
+  template<> struct MovePickerExt<true, false> : public MovePicker {
+
+    MovePickerExt(const Position& p, Move ttm, Depth d, const History& h,
+                  SearchStack* ss, Value b) : MovePicker(p, ttm, d, h, ss, b),
+                  mp(ss->sp->mp) {}
+
+    Move get_next_move() { return mp->get_next_move(); }
+
+    RootMoveList::iterator rm; // Dummy, needed to compile
+    MovePicker* mp;
+  };
+
+  // Default case, create and use a MovePicker object as source
+  template<> struct MovePickerExt<false, false> : public MovePicker {
+
+    MovePickerExt(const Position& p, Move ttm, Depth d, const History& h,
+                  SearchStack* ss, Value b) : MovePicker(p, ttm, d, h, ss, b) {}
+
+    RootMoveList::iterator rm; // Dummy, needed to compile
+  };
+
+} // namespace
 
 
 ////
@@ -406,7 +456,7 @@ int64_t perft(Position& pos, Depth depth)
 
 /// think() is the external interface to Stockfish's search, and is called when
 /// the program receives the UCI 'go' command. It initializes various
-/// search-related global variables, and calls root_search(). It returns false
+/// search-related global variables, and calls id_loop(). It returns false
 /// when a quit command is received during the search.
 
 bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[],
@@ -450,8 +500,6 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
 
   CheckExtension[1]         = Options["Check Extension (PV nodes)"].value<Depth>();
   CheckExtension[0]         = Options["Check Extension (non-PV nodes)"].value<Depth>();
-  SingleEvasionExtension[1] = Options["Single Evasion Extension (PV nodes)"].value<Depth>();
-  SingleEvasionExtension[0] = Options["Single Evasion Extension (non-PV nodes)"].value<Depth>();
   PawnPushTo7thExtension[1] = Options["Pawn Push to 7th Extension (PV nodes)"].value<Depth>();
   PawnPushTo7thExtension[0] = Options["Pawn Push to 7th Extension (non-PV nodes)"].value<Depth>();
   PassedPawnExtension[1]    = Options["Passed Pawn Extension (PV nodes)"].value<Depth>();
@@ -548,106 +596,97 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
 
 namespace {
 
-  // id_loop() is the main iterative deepening loop. It calls root_search
-  // repeatedly with increasing depth until the allocated thinking time has
-  // been consumed, the user stops the search, or the maximum search depth is
-  // reached.
+  // id_loop() is the main iterative deepening loop. It calls search() repeatedly
+  // with increasing depth until the allocated thinking time has been consumed,
+  // user stops the search, or the maximum search depth is reached.
 
   Move id_loop(Position& pos, Move searchMoves[], Move* ponderMove) {
 
     SearchStack ss[PLY_MAX_PLUS_2];
+    Value bestValues[PLY_MAX_PLUS_2];
+    int bestMoveChanges[PLY_MAX_PLUS_2];
+    int iteration, researchCountFL, researchCountFH, aspirationDelta;
+    Value value, alpha, beta;
     Depth depth;
-    Move EasyMove = MOVE_NONE;
-    Value value, alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
-    int researchCountFL, researchCountFH;
+    Move bestMove, easyMove;
 
     // Moves to search are verified, scored and sorted
-    RootMoveList rml(pos, searchMoves);
-    Rml = &rml;
+    Rml.init(pos, searchMoves);
+
+    // Initialize FIXME move before Rml.init()
+    TT.new_search();
+    H.clear();
+    memset(ss, 0, PLY_MAX_PLUS_2 * sizeof(SearchStack));
+    alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
+    *ponderMove = bestMove = easyMove = MOVE_NONE;
+    aspirationDelta = 0;
+    iteration = 1;
+    ss->currentMove = MOVE_NULL; // Hack to skip update_gains()
 
     // Handle special case of searching on a mate/stale position
-    if (rml.size() == 0)
+    if (Rml.size() == 0)
     {
-        Value s = (pos.is_check() ? -VALUE_MATE : VALUE_DRAW);
-
-        cout << "info depth " << 1
-             << " score " << value_to_uci(s) << endl;
+        cout << "info depth " << iteration << " score "
+             << value_to_uci(pos.is_check() ? -VALUE_MATE : VALUE_DRAW)
+             << endl;
 
         return MOVE_NONE;
     }
 
-    // Initialize
-    TT.new_search();
-    H.clear();
-    init_ss_array(ss, PLY_MAX_PLUS_2);
-    ValueByIteration[1] = rml[0].pv_score;
-    Iteration = 1;
-
-    // Send initial RootMoveList scoring (iteration 1)
+    // Send initial scoring (iteration 1)
     cout << set960(pos.is_chess960()) // Is enough to set once at the beginning
-         << "info depth " << Iteration
-         << "\n" << rml[0].pv_info_to_uci(pos, alpha, beta) << endl;
+         << "info depth " << iteration
+         << "\n" << Rml[0].pv_info_to_uci(pos, ONE_PLY, alpha, beta) << endl;
 
     // Is one move significantly better than others after initial scoring ?
-    if (   rml.size() == 1
-        || rml[0].pv_score > rml[1].pv_score + EasyMoveMargin)
-        EasyMove = rml[0].pv[0];
+    if (   Rml.size() == 1
+        || Rml[0].pv_score > Rml[1].pv_score + EasyMoveMargin)
+        easyMove = Rml[0].pv[0];
 
     // Iterative deepening loop
-    while (Iteration < PLY_MAX)
+    while (++iteration <= PLY_MAX && (!MaxDepth || iteration <= MaxDepth) && !StopRequest)
     {
-        // Initialize iteration
-        Iteration++;
-        BestMoveChangesByIteration[Iteration] = 0;
+        cout << "info depth " << iteration << endl;
 
-        cout << "info depth " << Iteration << endl;
+        Rml.bestMoveChanges = researchCountFL = researchCountFH = 0;
+        depth = (iteration - 1) * ONE_PLY;
 
         // Calculate dynamic aspiration window based on previous iterations
-        if (MultiPV == 1 && Iteration >= 6 && abs(ValueByIteration[Iteration - 1]) < VALUE_KNOWN_WIN)
+        if (MultiPV == 1 && iteration >= 6 && abs(bestValues[iteration - 1]) < VALUE_KNOWN_WIN)
         {
-            int prevDelta1 = ValueByIteration[Iteration - 1] - ValueByIteration[Iteration - 2];
-            int prevDelta2 = ValueByIteration[Iteration - 2] - ValueByIteration[Iteration - 3];
+            int prevDelta1 = bestValues[iteration - 1] - bestValues[iteration - 2];
+            int prevDelta2 = bestValues[iteration - 2] - bestValues[iteration - 3];
 
-            AspirationDelta = Max(abs(prevDelta1) + abs(prevDelta2) / 2, 16);
-            AspirationDelta = (AspirationDelta + 7) / 8 * 8; // Round to match grainSize
+            aspirationDelta = Max(abs(prevDelta1) + abs(prevDelta2) / 2, 16);
+            aspirationDelta = (aspirationDelta + 7) / 8 * 8; // Round to match grainSize
 
-            alpha = Max(ValueByIteration[Iteration - 1] - AspirationDelta, -VALUE_INFINITE);
-            beta  = Min(ValueByIteration[Iteration - 1] + AspirationDelta,  VALUE_INFINITE);
+            alpha = Max(bestValues[iteration - 1] - aspirationDelta, -VALUE_INFINITE);
+            beta  = Min(bestValues[iteration - 1] + aspirationDelta,  VALUE_INFINITE);
         }
 
-        depth = (Iteration - 2) * ONE_PLY + InitialDepth;
-
-        researchCountFL = researchCountFH = 0;
-
-        // We start with small aspiration window and in case of fail high/low, we
-        // research with bigger window until we are not failing high/low anymore.
+        // Start with a small aspiration window and, in case of fail high/low,
+        // research with bigger window until not failing high/low anymore.
         while (true)
         {
-            // Sort the moves before to (re)search
-            rml.set_non_pv_scores(pos, rml[0].pv[0], ss);
-            rml.sort();
-
-            // Search to the current depth, rml is updated and sorted
-            //value = root_search(pos, ss, alpha, beta, depth, rml);
-            value = search<PV, false, true>(pos, ss, alpha, beta, depth, 0);
-
-            // Sort the moves before to return
-            rml.sort();
+            // Search starting from ss+1 to allow calling update_gains()
+            value = search<PV, false, true>(pos, ss+1, alpha, beta, depth, 0);
 
             // Write PV lines to transposition table, in case the relevant entries
             // have been overwritten during the search.
-            for (int i = 0; i < Min(MultiPV, (int)rml.size()); i++)
-                rml[i].insert_pv_in_tt(pos);
+            for (int i = 0; i < Min(MultiPV, (int)Rml.size()); i++)
+                Rml[i].insert_pv_in_tt(pos);
 
+            // Value cannot be trusted. Break out immediately!
             if (StopRequest)
                 break;
 
             assert(value >= alpha);
 
+            // In case of failing high/low increase aspiration window and research,
+            // otherwise exit the fail high/low loop.
             if (value >= beta)
             {
-                // Prepare for a research after a fail high, each time with a wider window
-                beta = Min(beta + AspirationDelta * (1 << researchCountFH), VALUE_INFINITE);
+                beta = Min(beta + aspirationDelta * (1 << researchCountFH), VALUE_INFINITE);
                 researchCountFH++;
             }
             else if (value <= alpha)
@@ -655,61 +694,56 @@ namespace {
                 AspirationFailLow = true;
                 StopOnPonderhit = false;
 
-                // Prepare for a research after a fail low, each time with a wider window
-                alpha = Max(alpha - AspirationDelta * (1 << researchCountFL), -VALUE_INFINITE);
+                alpha = Max(alpha - aspirationDelta * (1 << researchCountFL), -VALUE_INFINITE);
                 researchCountFL++;
             }
             else
                 break;
         }
 
-        if (StopRequest)
-            break; // Value cannot be trusted. Break out immediately!
-
-        //Save info about search result
-        ValueByIteration[Iteration] = value;
+        // Collect info about search result
+        bestMove = Rml[0].pv[0];
+        bestValues[iteration] = value;
+        bestMoveChanges[iteration] = Rml.bestMoveChanges;
 
         // Drop the easy move if differs from the new best move
-        if (rml[0].pv[0] != EasyMove)
-            EasyMove = MOVE_NONE;
+        if (bestMove != easyMove)
+            easyMove = MOVE_NONE;
 
-        if (UseTimeManagement)
+        if (UseTimeManagement && !StopRequest)
         {
             // Time to stop?
-            bool stopSearch = false;
-
-            // Stop search early if there is only a single legal move,
-            // we search up to Iteration 6 anyway to get a proper score.
-            if (Iteration >= 6 && rml.size() == 1)
-                stopSearch = true;
+            bool noMoreTime = false;
 
             // Stop search early when the last two iterations returned a mate score
-            if (   Iteration >= 6
-                && abs(ValueByIteration[Iteration]) >= abs(VALUE_MATE) - 100
-                && abs(ValueByIteration[Iteration-1]) >= abs(VALUE_MATE) - 100)
-                stopSearch = true;
-
-            // Stop search early if one move seems to be much better than the others
-            if (   Iteration >= 8
-                && EasyMove == rml[0].pv[0]
-                && (  (   rml[0].nodes > (pos.nodes_searched() * 85) / 100
+            if (   iteration >= 6
+                && abs(bestValues[iteration])   >= abs(VALUE_MATE) - 100
+                && abs(bestValues[iteration-1]) >= abs(VALUE_MATE) - 100)
+                noMoreTime = true;
+
+            // Stop search early if one move seems to be much better than the
+            // others or if there is only a single legal move. In this latter
+            // case we search up to Iteration 8 anyway to get a proper score.
+            if (   iteration >= 8
+                && easyMove == bestMove
+                && (   Rml.size() == 1
+                    ||(   Rml[0].nodes > (pos.nodes_searched() * 85) / 100
                        && current_search_time() > TimeMgr.available_time() / 16)
-                    ||(   rml[0].nodes > (pos.nodes_searched() * 98) / 100
+                    ||(   Rml[0].nodes > (pos.nodes_searched() * 98) / 100
                        && current_search_time() > TimeMgr.available_time() / 32)))
-                stopSearch = true;
+                noMoreTime = true;
 
             // Add some extra time if the best move has changed during the last two iterations
-            if (Iteration > 5 && Iteration <= 50)
-                TimeMgr.pv_instability(BestMoveChangesByIteration[Iteration],
-                                       BestMoveChangesByIteration[Iteration-1]);
+            if (iteration > 5 && iteration <= 50)
+                TimeMgr.pv_instability(bestMoveChanges[iteration], bestMoveChanges[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() > (TimeMgr.available_time() * 80) / 128)
-                stopSearch = true;
+                noMoreTime = true;
 
-            if (stopSearch)
+            if (noMoreTime)
             {
                 if (Pondering)
                     StopOnPonderhit = true;
@@ -717,235 +751,10 @@ namespace {
                     break;
             }
         }
-
-        if (MaxDepth && Iteration >= MaxDepth)
-            break;
     }
 
-    *ponderMove = rml[0].pv[1];
-    return rml[0].pv[0];
-  }
-
-
-  // root_search() is the function which searches the root node. It is
-  // similar to search_pv except that it prints some information to the
-  // standard output and handles the fail low/high loops.
-
-  Value root_search(Position& pos, SearchStack* ss, Value alpha,
-                    Value beta, Depth depth, RootMoveList& rml) {
-
-    assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
-    assert(beta > alpha && beta <= VALUE_INFINITE);
-    assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
-
-    Move movesSearched[MOVES_MAX];
-    StateInfo st;
-    Key posKey;
-    Move move;
-    Depth ext, newDepth;
-    ValueType vt;
-    Value bestValue, value, oldAlpha;
-    bool isCheck, moveIsCheck, captureOrPromotion, dangerous, isPvMove;
-    int moveCount = 0;
-
-    bestValue = value = -VALUE_INFINITE;
-    oldAlpha = alpha;
-    isCheck = pos.is_check();
-
-    // Step 1. Initialize node (polling is omitted at root)
-    ss->currentMove = ss->bestMove = MOVE_NONE;
-    (ss+2)->killers[0] = (ss+2)->killers[1] = (ss+2)->mateKiller = 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)
-    posKey = pos.get_key();
-
-    // Step 5. Evaluate the position statically
-    // At root we do this only to get reference value for child nodes
-    ss->evalMargin = VALUE_NONE;
-    ss->eval = isCheck ? VALUE_NONE : evaluate(pos, ss->evalMargin);
-
-    // Step 6. Razoring (omitted at root)
-    // Step 7. Static null move pruning (omitted at root)
-    // Step 8. Null move search with verification search (omitted at root)
-    // Step 9. Internal iterative deepening (omitted at root)
-
-    CheckInfo ci(pos);
-    int64_t nodes;
-    RootMoveList::iterator rm = rml.begin();
-    bestValue = alpha;
-
-    // Step 10. Loop through moves
-    // Loop through all legal moves until no moves remain or a beta cutoff occurs
-    while (   bestValue < beta
-           && rm != rml.end()
-           && !StopRequest)
-    {
-        move = ss->currentMove = rm->pv[0];
-        movesSearched[moveCount++] = move;
-        isPvMove = (moveCount <= MultiPV);
-
-        // This is used by time management
-        FirstRootMove = (rm == rml.begin());
-
-        // Save the current node count before the move is searched
-        nodes = pos.nodes_searched();
-
-        // If it's time to send nodes info, do it here where we have the
-        // correct accumulated node counts searched by each thread.
-        if (SendSearchedNodes)
-        {
-            SendSearchedNodes = false;
-            cout << "info nodes " << nodes
-                 << " nps " << nps(pos)
-                 << " time " << current_search_time() << endl;
-        }
-
-        if (current_search_time() >= 1000)
-            cout << "info currmove " << move
-                 << " currmovenumber " << moveCount << endl;
-
-        moveIsCheck = pos.move_is_check(move);
-        captureOrPromotion = pos.move_is_capture_or_promotion(move);
-
-        // Step 11. Decide the new search depth
-        ext = extension<PV>(pos, move, captureOrPromotion, moveIsCheck, false, false, &dangerous);
-        newDepth = depth + ext;
-
-        // Step 12. Futility pruning (omitted at root)
-        // Step 13. Make the move
-        pos.do_move(move, st, ci, moveIsCheck);
-
-        // Step extra. pv search
-        // We do pv search for PV moves
-        if (isPvMove)
-        {
-            // Aspiration window is disabled in multi-pv case
-            if (MultiPV > 1)
-                alpha = -VALUE_INFINITE;
-
-            // Full depth PV search, done on first move or after a fail high
-            value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, 1);
-        }
-        else
-        {
-            // Step 14. Reduced search
-            // if the move fails high will be re-searched at full depth
-            bool doFullDepthSearch = true;
-
-            if (    depth >= 3 * ONE_PLY
-                && !captureOrPromotion
-                && !dangerous
-                && !move_is_castle(move)
-                &&  ss->killers[0] != move
-                &&  ss->killers[1] != move)
-            {
-                ss->reduction = reduction<PV>(depth, moveCount - MultiPV + 1);
-
-                if (ss->reduction)
-                {
-                    Depth d = newDepth - ss->reduction;
-                    value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, 1);
-
-                    doFullDepthSearch = (value > alpha);
-                }
-                ss->reduction = DEPTH_ZERO; // Restore original reduction
-            }
-
-            // Step 15. Full depth search
-            if (doFullDepthSearch)
-            {
-                // Full depth non-pv search using alpha as upperbound
-                value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, 1);
-
-                // If we are above alpha then research at same depth but as PV
-                // to get a correct score or eventually a fail high above beta.
-                if (value > alpha)
-                    value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, 1);
-            }
-        }
-
-        // Step 16. Undo move
-        pos.undo_move(move);
-
-        assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
-
-        // Finished searching the move. If StopRequest 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 break out of the loop without updating the best
-        // move and/or PV.
-        if (StopRequest)
-            break;
-
-        // Remember searched nodes counts for this move
-        rm->nodes += pos.nodes_searched() - nodes;
-
-        // Step 17. Check for new best move
-        if (!isPvMove && value <= alpha)
-            rm->pv_score = -VALUE_INFINITE;
-        else
-        {
-            // PV move or new best move!
-
-            // Update PV
-            ss->bestMove = move;
-            rm->pv_score = value;
-            rm->extract_pv_from_tt(pos);
-
-            // We record how often the best move has been changed in each
-            // iteration. This information is used for time managment: When
-            // the best move changes frequently, we allocate some more time.
-            if (!isPvMove && MultiPV == 1)
-                BestMoveChangesByIteration[Iteration]++;
-
-            // Inform GUI that PV has changed, in case of multi-pv UCI protocol
-            // requires we send all the PV lines properly sorted.
-            rml.sort_multipv(moveCount);
-
-            for (int j = 0; j < Min(MultiPV, (int)rml.size()); j++)
-                cout << rml[j].pv_info_to_uci(pos, alpha, beta, j) << endl;
-
-            // Update alpha. In multi-pv we don't use aspiration window
-            if (MultiPV == 1)
-            {
-                // Raise alpha to setup proper non-pv search upper bound
-                if (value > alpha)
-                    alpha = bestValue = value;
-            }
-            else // Set alpha equal to minimum score among the PV lines
-                alpha = bestValue = rml[Min(moveCount, MultiPV) - 1].pv_score; // FIXME why moveCount?
-
-        } // PV move or new best move
-
-        ++rm;
-
-    } // Root moves loop
-
-    // Step 20. Update tables
-    // If the search is not aborted, update the transposition table,
-    // history counters, and killer moves.
-    if (!StopRequest)
-    {
-        move = bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove;
-        vt   = bestValue <= oldAlpha ? VALUE_TYPE_UPPER
-             : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT;
-
-        TT.store(posKey, value_to_tt(bestValue, 0), vt, depth, move, ss->eval, ss->evalMargin);
-
-        // Update killers and history only for non capture moves that fails high
-        if (    bestValue >= beta
-            && !pos.move_is_capture_or_promotion(move))
-        {
-            update_history(pos, move, depth, movesSearched, moveCount);
-            update_killers(move, ss->killers);
-        }
-    }
-
-    assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
-
-    return bestValue;
+    *ponderMove = Rml[0].pv[1];
+    return bestMove;
   }
 
 
@@ -967,7 +776,6 @@ namespace {
 
     Move movesSearched[MOVES_MAX];
     int64_t nodes;
-    RootMoveList::iterator rm;
     StateInfo st;
     const TTEntry *tte;
     Key posKey;
@@ -976,9 +784,9 @@ namespace {
     ValueType vt;
     Value bestValue, value, oldAlpha;
     Value refinedValue, nullValue, futilityBase, futilityValueScaled; // Non-PV specific
-    bool isPvMove, isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous;
+    bool isPvMove, isCheck, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous;
     bool mateThreat = false;
-    int moveCount = 0;
+    int moveCount = 0, playedMoveCount = 0;
     int threadID = pos.thread();
     SplitPoint* sp = NULL;
 
@@ -995,36 +803,33 @@ namespace {
         mateThreat = sp->mateThreat;
         goto split_point_start;
     }
-    else {} // Hack to fix icc's "statement is unreachable" warning
+    else if (Root)
+        bestValue = alpha;
 
     // Step 1. Initialize node and poll. Polling can abort search
     ss->currentMove = ss->bestMove = threatMove = MOVE_NONE;
     (ss+2)->killers[0] = (ss+2)->killers[1] = (ss+2)->mateKiller = MOVE_NONE;
 
-    if (!Root)
+    if (threadID == 0 && ++NodesSincePoll > NodesBetweenPolls)
     {
-        if (threadID == 0 && ++NodesSincePoll > NodesBetweenPolls)
-        {
-            NodesSincePoll = 0;
-            poll(pos);
-        }
-
-        // Step 2. Check for aborted search and immediate draw
-        if (   StopRequest
-            || ThreadsMgr.cutoff_at_splitpoint(threadID)
-            || pos.is_draw()
-            || ply >= PLY_MAX - 1)
-            return VALUE_DRAW;
-
-        // Step 3. Mate distance pruning
-        alpha = Max(value_mated_in(ply), alpha);
-        beta = Min(value_mate_in(ply+1), beta);
-        if (alpha >= beta)
-            return alpha;
+        NodesSincePoll = 0;
+        poll(pos);
     }
 
-    // Step 4. Transposition table lookup
+    // Step 2. Check for aborted search and immediate draw
+    if ((   StopRequest
+         || ThreadsMgr.cutoff_at_splitpoint(threadID)
+         || pos.is_draw()
+         || ply >= PLY_MAX - 1) && !Root)
+        return VALUE_DRAW;
+
+    // Step 3. Mate distance pruning
+    alpha = Max(value_mated_in(ply), alpha);
+    beta = Min(value_mate_in(ply+1), beta);
+    if (alpha >= beta)
+        return alpha;
 
+    // Step 4. Transposition table lookup
     // We don't want the score of a partial search to overwrite a previous full search
     // TT value, so we use a different position key in case of an excluded move exists.
     excludedMove = ss->excludedMove;
@@ -1066,8 +871,7 @@ namespace {
     }
 
     // Save gain for the parent non-capture move
-    if (!Root)
-        update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
+    update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
 
     // Step 6. Razoring (is omitted in PV nodes)
     if (   !PvNode
@@ -1160,9 +964,8 @@ namespace {
     }
 
     // Step 9. Internal iterative deepening
-    if (   !Root
-        &&  depth >= IIDDepth[PvNode]
-        &&  ttMove == MOVE_NONE
+    if (   depth >= IIDDepth[PvNode]
+        && ttMove == MOVE_NONE
         && (PvNode || (!isCheck && ss->eval >= beta - IIDMargin)))
     {
         Depth d = (PvNode ? depth - 2 * ONE_PLY : depth / 2);
@@ -1176,18 +979,15 @@ namespace {
     }
 
     // Expensive mate threat detection (only for PV nodes)
-    if (PvNode && !Root) // FIXME
+    if (PvNode)
         mateThreat = pos.has_mate_threat();
 
 split_point_start: // At split points actual search starts from here
 
     // Initialize a MovePicker object for the current position
-    // FIXME currently MovePicker() c'tor is needless called also in SplitPoint
-    MovePicker mpBase(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
-    MovePicker& mp = SpNode ? *sp->mp : mpBase;
+    MovePickerExt<SpNode, Root> mp(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
     CheckInfo ci(pos);
     ss->bestMove = MOVE_NONE;
-    singleEvasion = !SpNode && isCheck && mp.number_of_evasions() == 1;
     futilityBase = ss->eval + ss->evalMargin;
     singularExtensionNode =   !Root
                            && !SpNode
@@ -1197,12 +997,6 @@ split_point_start: // At split points actual search starts from here
                            && !excludedMove // Do not allow recursive singular extension search
                            && (tte->type() & VALUE_TYPE_LOWER)
                            && tte->depth() >= depth - 3 * ONE_PLY;
-    if (Root)
-    {
-        rm = Rml->begin();
-        bestValue = alpha;
-    }
-
     if (SpNode)
     {
         lock_grab(&(sp->lock));
@@ -1212,16 +1006,25 @@ split_point_start: // At split points actual search starts from here
     // Step 10. Loop through moves
     // Loop through all legal moves until no moves remain or a beta cutoff occurs
     while (   bestValue < beta
-           && (!Root || rm != Rml->end())
-           && ( Root || (move = mp.get_next_move()) != MOVE_NONE)
+           && (move = mp.get_next_move()) != MOVE_NONE
            && !ThreadsMgr.cutoff_at_splitpoint(threadID))
     {
-      if (Root)
+      assert(move_is_ok(move));
+
+      if (SpNode)
       {
-          move = rm->pv[0];
+          moveCount = ++sp->moveCount;
+          lock_release(&(sp->lock));
+      }
+      else if (move == excludedMove)
+          continue;
+      else
+          moveCount++;
 
+      if (Root)
+      {
           // This is used by time management
-          FirstRootMove = (rm == Rml->begin());
+          FirstRootMove = (moveCount == 1);
 
           // Save the current node count before the move is searched
           nodes = pos.nodes_searched();
@@ -1241,24 +1044,12 @@ split_point_start: // At split points actual search starts from here
                    << " currmovenumber " << moveCount << endl;
       }
 
-      assert(move_is_ok(move));
-
-      if (SpNode)
-      {
-          moveCount = ++sp->moveCount;
-          lock_release(&(sp->lock));
-      }
-      else if (move == excludedMove)
-          continue;
-      else
-          movesSearched[moveCount++] = move;
-
       isPvMove = (PvNode && moveCount <= (Root ? MultiPV : 1));
       moveIsCheck = pos.move_is_check(move, ci);
       captureOrPromotion = pos.move_is_capture_or_promotion(move);
 
       // Step 11. Decide the new search depth
-      ext = extension<PvNode>(pos, move, captureOrPromotion, moveIsCheck, singleEvasion, mateThreat, &dangerous);
+      ext = extension<PvNode>(pos, move, captureOrPromotion, moveIsCheck, mateThreat, &dangerous);
 
       // Singular extension search. If all moves but one fail low on a search of (alpha-s, beta-s),
       // and just one fails high on (alpha, beta), then that move is singular and should be extended.
@@ -1343,6 +1134,9 @@ split_point_start: // At split points actual search starts from here
       // Step 13. Make the move
       pos.do_move(move, st, ci, moveIsCheck);
 
+      if (!SpNode && !captureOrPromotion)
+          movesSearched[playedMoveCount++] = move;
+
       // Step extra. pv search (only in PV nodes)
       // The first move in list is the expected PV
       if (isPvMove)
@@ -1437,6 +1231,10 @@ split_point_start: // At split points actual search starts from here
 
       if (Root)
       {
+          // To avoid to exit with bestValue == -VALUE_INFINITE
+          if (value > bestValue)
+              bestValue = value;
+
           // Finished searching the move. If StopRequest 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
@@ -1446,46 +1244,41 @@ split_point_start: // At split points actual search starts from here
               break;
 
           // Remember searched nodes counts for this move
-          rm->nodes += pos.nodes_searched() - nodes;
+          mp.rm->nodes += pos.nodes_searched() - nodes;
 
           // Step 17. Check for new best move
           if (!isPvMove && value <= alpha)
-              rm->pv_score = -VALUE_INFINITE;
+              mp.rm->pv_score = -VALUE_INFINITE;
           else
           {
               // PV move or new best move!
 
               // Update PV
               ss->bestMove = move;
-              rm->pv_score = value;
-              rm->extract_pv_from_tt(pos);
+              mp.rm->pv_score = value;
+              mp.rm->extract_pv_from_tt(pos);
 
               // We record how often the best move has been changed in each
               // iteration. This information is used for time managment: When
               // the best move changes frequently, we allocate some more time.
               if (!isPvMove && MultiPV == 1)
-                  BestMoveChangesByIteration[Iteration]++;
+                  Rml.bestMoveChanges++;
 
               // Inform GUI that PV has changed, in case of multi-pv UCI protocol
               // requires we send all the PV lines properly sorted.
-              Rml->sort_multipv(moveCount);
+              Rml.sort_multipv(moveCount);
 
-              for (int j = 0; j < Min(MultiPV, (int)Rml->size()); j++)
-                  cout << (*Rml)[j].pv_info_to_uci(pos, alpha, beta, j) << endl;
+              for (int j = 0; j < Min(MultiPV, (int)Rml.size()); j++)
+                  cout << Rml[j].pv_info_to_uci(pos, depth, alpha, beta, j) << endl;
 
-              // Update alpha. In multi-pv we don't use aspiration window
-              if (MultiPV == 1)
-              {
-                  // Raise alpha to setup proper non-pv search upper bound
-                  if (value > alpha)
-                      alpha = bestValue = value;
-              }
-              else // Set alpha equal to minimum score among the PV lines
-                  alpha = bestValue = (*Rml)[Min(moveCount, MultiPV) - 1].pv_score; // FIXME why moveCount?
+              // Update alpha. In multi-pv we don't use aspiration window, so
+              // set alpha equal to minimum score among the PV lines.
+              if (MultiPV > 1)
+                  alpha = Rml[Min(moveCount, MultiPV) - 1].pv_score; // FIXME why moveCount?
+              else if (value > alpha)
+                  alpha = value;
 
           } // PV move or new best move
-
-          ++rm;
       }
 
       // Step 18. Check for split
@@ -1496,8 +1289,7 @@ split_point_start: // At split points actual search starts from here
           && bestValue < beta
           && ThreadsMgr.available_thread_exists(threadID)
           && !StopRequest
-          && !ThreadsMgr.cutoff_at_splitpoint(threadID)
-          && Iteration <= 99)
+          && !ThreadsMgr.cutoff_at_splitpoint(threadID))
           ThreadsMgr.split<FakeSplit>(pos, ss, ply, &alpha, beta, &bestValue, depth,
                                       threatMove, mateThreat, moveCount, &mp, PvNode);
     }
@@ -1524,7 +1316,7 @@ split_point_start: // At split points actual search starts from here
         if (    bestValue >= beta
             && !pos.move_is_capture_or_promotion(move))
         {
-            update_history(pos, move, depth, movesSearched, moveCount);
+            update_history(pos, move, depth, movesSearched, playedMoveCount);
             update_killers(move, ss->killers);
         }
     }
@@ -1727,6 +1519,26 @@ split_point_start: // At split points actual search starts from here
   }
 
 
+  // qsearch_scoring() scores each move of a list using a qsearch() evaluation,
+  // it is used in RootMoveList to get an initial scoring.
+  void qsearch_scoring(Position& pos, MoveStack* mlist, MoveStack* last) {
+
+    SearchStack ss[PLY_MAX_PLUS_2];
+    StateInfo st;
+
+    memset(ss, 0, 4 * sizeof(SearchStack));
+    ss[0].eval = ss[0].evalMargin = VALUE_NONE;
+
+    for (MoveStack* cur = mlist; cur != last; cur++)
+    {
+        ss[0].currentMove = cur->move;
+        pos.do_move(cur->move, st);
+        cur->score = -qsearch<PV>(pos, ss+1, -VALUE_INFINITE, VALUE_INFINITE, DEPTH_ZERO, 1);
+        pos.undo_move(cur->move);
+    }
+  }
+
+
   // 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.
@@ -1887,22 +1699,19 @@ split_point_start: // At split points actual search starts from here
   // extended, as example because the corresponding UCI option is set to zero,
   // the move is marked as 'dangerous' so, at least, we avoid to prune it.
   template <NodeType PvNode>
-  Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck,
-                  bool singleEvasion, bool mateThreat, bool* dangerous) {
+  Depth extension(const Position& pos, Move m, bool captureOrPromotion,
+                  bool moveIsCheck, bool mateThreat, bool* dangerous) {
 
     assert(m != MOVE_NONE);
 
     Depth result = DEPTH_ZERO;
-    *dangerous = moveIsCheck | singleEvasion | mateThreat;
+    *dangerous = moveIsCheck | mateThreat;
 
     if (*dangerous)
     {
         if (moveIsCheck && pos.see_sign(m) >= 0)
             result += CheckExtension[PvNode];
 
-        if (singleEvasion)
-            result += SingleEvasionExtension[PvNode];
-
         if (mateThreat)
             result += MateThreatExtension[PvNode];
     }
@@ -2036,8 +1845,7 @@ split_point_start: // At split points actual search starts from here
 
         assert(m != move);
 
-        if (!pos.move_is_capture_or_promotion(m))
-            H.update(pos.piece_on(move_from(m)), move_to(m), -bonus);
+        H.update(pos.piece_on(move_from(m)), move_to(m), -bonus);
     }
   }
 
@@ -2047,11 +1855,11 @@ split_point_start: // At split points actual search starts from here
 
   void update_killers(Move m, Move killers[]) {
 
-    if (m == killers[0])
-        return;
-
-    killers[1] = killers[0];
-    killers[0] = m;
+    if (m != killers[0])
+    {
+        killers[1] = killers[0];
+        killers[0] = m;
+    }
   }
 
 
@@ -2069,24 +1877,6 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // init_ss_array() does a fast reset of the first entries of a SearchStack
-  // array and of all the excludedMove and skipNullMove entries.
-
-  void init_ss_array(SearchStack* ss, int size) {
-
-    for (int i = 0; i < size; i++, ss++)
-    {
-        ss->excludedMove = MOVE_NONE;
-        ss->skipNullMove = false;
-        ss->reduction = DEPTH_ZERO;
-        ss->sp = NULL;
-
-        if (i < 3)
-            ss->killers[0] = ss->killers[1] = ss->mateKiller = MOVE_NONE;
-    }
-  }
-
-
   // value_to_uci() converts a value to a string suitable for use with the UCI
   // protocol specifications:
   //
@@ -2752,7 +2542,7 @@ split_point_start: // At split points actual search starts from here
   // formatted according to UCI specification and eventually writes the info
   // to a log file. It is called at each iteration or after a new pv is found.
 
-  std::string RootMove::pv_info_to_uci(Position& pos, Value alpha, Value beta, int pvLine) {
+  std::string RootMove::pv_info_to_uci(Position& pos, Depth depth, Value alpha, Value beta, int pvLine) {
 
     std::stringstream s, l;
     Move* m = pv;
@@ -2760,7 +2550,7 @@ split_point_start: // At split points actual search starts from here
     while (*m != MOVE_NONE)
         l << *m++ << " ";
 
-    s << "info depth " << Iteration // FIXME
+    s << "info depth " << depth / ONE_PLY
       << " seldepth " << int(m - pv)
       << " multipv " << pvLine + 1
       << " score " << value_to_uci(pv_score)
@@ -2775,25 +2565,23 @@ split_point_start: // At split points actual search starts from here
         ValueType t = pv_score >= beta  ? VALUE_TYPE_LOWER :
                       pv_score <= alpha ? VALUE_TYPE_UPPER : VALUE_TYPE_EXACT;
 
-        LogFile << pretty_pv(pos, current_search_time(), Iteration, pv_score, t, pv) << endl;
+        LogFile << pretty_pv(pos, current_search_time(), depth / ONE_PLY, pv_score, t, pv) << endl;
     }
     return s.str();
   }
 
 
-  RootMoveList::RootMoveList(Position& pos, Move searchMoves[]) {
+  void RootMoveList::init(Position& pos, Move searchMoves[]) {
 
-    SearchStack ss[PLY_MAX_PLUS_2];
     MoveStack mlist[MOVES_MAX];
-    StateInfo st;
     Move* sm;
 
-    // Initialize search stack
-    init_ss_array(ss, PLY_MAX_PLUS_2);
-    ss[0].eval = ss[0].evalMargin = VALUE_NONE;
+    clear();
+    bestMoveChanges = 0;
 
-    // Generate all legal moves
+    // Generate all legal moves and score them
     MoveStack* last = generate<MV_LEGAL>(pos, mlist);
+    qsearch_scoring(pos, mlist, last);
 
     // Add each move to the RootMoveList's vector
     for (MoveStack* cur = mlist; cur != last; cur++)
@@ -2805,38 +2593,13 @@ split_point_start: // At split points actual search starts from here
         if (searchMoves[0] && *sm != cur->move)
             continue;
 
-        // Find a quick score for the move and add to the list
-        pos.do_move(cur->move, st);
-
         RootMove rm;
-        rm.pv[0] = ss[0].currentMove = cur->move;
+        rm.pv[0] = cur->move;
         rm.pv[1] = MOVE_NONE;
-        rm.pv_score = -qsearch<PV>(pos, ss+1, -VALUE_INFINITE, VALUE_INFINITE, DEPTH_ZERO, 1);
+        rm.pv_score = Value(cur->score);
         push_back(rm);
-
-        pos.undo_move(cur->move);
     }
     sort();
   }
 
-  // Score root moves using the standard way used in main search, the moves
-  // are scored according to the order in which are returned by MovePicker.
-  // This is the second order score that is used to compare the moves when
-  // the first order pv scores of both moves are equal.
-
-  void RootMoveList::set_non_pv_scores(const Position& pos, Move ttm, SearchStack* ss)
-  {
-      Move move;
-      Value score = VALUE_ZERO;
-      MovePicker mp(pos, ttm, ONE_PLY, H, ss);
-
-      while ((move = mp.get_next_move()) != MOVE_NONE)
-          for (Base::iterator it = begin(); it != end(); ++it)
-              if (it->pv[0] == move)
-              {
-                  it->non_pv_score = score--;
-                  break;
-              }
-  }
-
 } // namespace