]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Additional cleanup in id_loop()
[stockfish] / src / search.cpp
index cdd38407c6dff60b23c166e812d20d2da80f1659..2adc2e0973e2d7778635f7fd03226a3ed55318db 100644 (file)
 #include "evaluate.h"
 #include "history.h"
 #include "misc.h"
+#include "move.h"
 #include "movegen.h"
 #include "movepick.h"
 #include "lock.h"
-#include "san.h"
 #include "search.h"
 #include "timeman.h"
 #include "thread.h"
@@ -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(const 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,13 @@ namespace {
 
     typedef std::vector<RootMove> Base;
 
-    RootMoveList(Position& pos, Move searchMoves[]);
+    void init(Position& pos, Move searchMoves[]);
     void set_non_pv_scores(const Position& pos, Move ttm, SearchStack* ss);
 
     void sort() { insertion_sort<RootMove, Base::iterator>(begin(), end()); }
     void sort_multipv(int n) { insertion_sort<RootMove, Base::iterator>(begin(), begin() + n); }
+
+    int bestMoveChanges;
   };
 
 
@@ -170,8 +172,11 @@ namespace {
 
   // Overload operator << for moves to make it easier to print moves in
   // coordinate notation compatible with UCI protocol.
+  std::ostream& operator<<(std::ostream& os, Move m) {
 
-  std::ostream& operator<<(std::ostream& os, Move m);
+    bool chess960 = (os.iword(0) != 0); // See set960()
+    return os << move_to_uci(m, chess960);
+  }
 
 
   /// Adjustments
@@ -245,15 +250,8 @@ namespace {
   // Book object
   Book OpeningBook;
 
-  // 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;
+  // Pointer to root move list
+  RootMoveList Rml;
 
   // MultiPV mode
   int MultiPV;
@@ -283,9 +281,8 @@ 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>
+  template <NodeType PvNode, bool SpNode, bool Root>
   Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply);
 
   template <NodeType PvNode>
@@ -295,7 +292,7 @@ namespace {
   inline Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) {
 
       return depth < ONE_PLY ? qsearch<PvNode>(pos, ss, alpha, beta, DEPTH_ZERO, ply)
-                             : search<PvNode, false>(pos, ss, alpha, beta, depth, ply);
+                             : search<PvNode, false, false>(pos, ss, alpha, beta, depth, ply);
   }
 
   template <NodeType PvNode>
@@ -326,7 +323,54 @@ namespace {
   DWORD WINAPI init_thread(LPVOID threadID);
 #endif
 
-}
+
+  // A dispatcher to choose among different move sources according to the type of node
+  template<bool SpNode, bool Root> struct MovePickerExt;
+
+  // In Root nodes use RootMoveList Rml as source
+  template<> struct MovePickerExt<false, true> {
+
+      MovePickerExt(const Position&, Move, Depth, const History&, SearchStack*, Value)
+                  : rm(Rml.begin()), firstCall(true) {}
+
+      Move get_next_move() {
+
+        if (!firstCall)
+            ++rm;
+        else
+            firstCall = false;
+
+        return rm != Rml.end() ? rm->pv[0] : MOVE_NONE;
+      }
+      int number_of_evasions() const { return (int)Rml.size(); }
+
+      RootMoveList::iterator rm;
+      bool firstCall;
+  };
+
+  // In SpNodes use split point's shared MovePicker as move source
+  template<> struct MovePickerExt<true, false> {
+
+      MovePickerExt(const Position&, Move, Depth, const History&, SearchStack* ss, Value)
+                  : mp(ss->sp->mp) {}
+
+      Move get_next_move() { return mp->get_next_move(); }
+      int number_of_evasions() const { return mp->number_of_evasions(); }
+
+      RootMoveList::iterator rm; // Dummy, never used
+      MovePicker* mp;
+  };
+
+  // Normal 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 beta) : MovePicker(p, ttm, d, h, ss, beta) {}
+
+      RootMoveList::iterator rm; // Dummy, never used
+  };
+
+} // namespace
 
 
 ////
@@ -400,7 +444,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[],
@@ -420,7 +464,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   // Look for a book move, only during games, not tests
   if (UseTimeManagement && Options["OwnBook"].value<bool>())
   {
-      if (Options["Book File"].value<std::string>() != OpeningBook.file_name())
+      if (Options["Book File"].value<std::string>() != OpeningBook.name())
           OpeningBook.open(Options["Book File"].value<std::string>());
 
       Move bookMove = OpeningBook.get_move(pos, Options["Best Book Move"].value<bool>());
@@ -542,7 +586,7 @@ 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
+  // id_loop() is the main iterative deepening loop. It calls 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.
@@ -550,115 +594,153 @@ namespace {
   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;
+    Move EasyMove;
 
     // Moves to search are verified, scored and sorted
-    RootMoveList rml(pos, searchMoves);
+    Rml.init(pos, searchMoves);
+
+    // Initialize FIXME move before Rml.init()
+    TT.new_search();
+    H.clear();
+    init_ss_array(ss, PLY_MAX_PLUS_2);
+    alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
+    EasyMove = MOVE_NONE;
+    aspirationDelta = 0;
+    iteration = 1;
 
     // 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 - 2) * ONE_PLY + InitialDepth;
 
         // 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;
+        // 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.
+        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
+            value = search<PV, false, true>(pos, ss, alpha, beta, depth, 0);
+
+            // Sort the moves and write PV lines to transposition table, in case
+            // the relevant entries have been overwritten during the search.
+            Rml.sort();
+            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);
 
-        // Search to the current depth, rml is updated and sorted
-        value = root_search(pos, ss, alpha, beta, depth, rml);
+            bestMoveChanges[iteration] = Rml.bestMoveChanges; // FIXME move outside fail high/low loop
 
-        if (StopRequest)
-            break; // Value cannot be trusted. Break out immediately!
+            // In case of failing high/low increase aspiration window and research,
+            // otherwise exit the fail high/low loop.
+            if (value >= beta)
+            {
+                beta = Min(beta + aspirationDelta * (1 << researchCountFH), VALUE_INFINITE);
+                researchCountFH++;
+            }
+            else if (value <= alpha)
+            {
+                AspirationFailLow = true;
+                StopOnPonderhit = false;
+
+                alpha = Max(alpha - aspirationDelta * (1 << researchCountFL), -VALUE_INFINITE);
+                researchCountFL++;
+            }
+            else
+                break;
+        }
 
         //Save info about search result
-        ValueByIteration[Iteration] = value;
+        bestValues[iteration] = value;
 
         // Drop the easy move if differs from the new best move
-        if (rml[0].pv[0] != EasyMove)
+        if (Rml[0].pv[0] != EasyMove)
             EasyMove = MOVE_NONE;
 
-        if (UseTimeManagement)
+        if (UseTimeManagement && !StopRequest)
         {
             // Time to stop?
-            bool stopSearch = false;
+            bool noMoreTime = 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;
+            if (iteration >= 6 && Rml.size() == 1)
+                noMoreTime = true;
 
             // 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;
+            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
-            if (   Iteration >= 8
-                && EasyMove == rml[0].pv[0]
-                && (  (   rml[0].nodes > (pos.nodes_searched() * 85) / 100
+            if (   iteration >= 8
+                && EasyMove == Rml[0].pv[0]
+                && (  (   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;
@@ -666,267 +748,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) {
-    StateInfo st;
-    Move movesSearched[MOVES_MAX];
-    CheckInfo ci(pos);
-    int64_t nodes;
-    Move move;
-    Depth ext, newDepth;
-    Value value, oldAlpha;
-    RootMoveList::iterator rm;
-    bool isCheck, moveIsCheck, captureOrPromotion, dangerous, isPvMove;
-    int moveCount, researchCountFH, researchCountFL;
-
-    researchCountFH = researchCountFL = 0;
-    oldAlpha = alpha;
-    isCheck = pos.is_check();
-
-    // Step 1. Initialize node (polling is omitted at root)
-    ss->currentMove = ss->bestMove = MOVE_NONE;
-
-    // Step 2. Check for aborted search (omitted at root)
-    // Step 3. Mate distance pruning (omitted at root)
-    // Step 4. Transposition table lookup (omitted at root)
-
-    // Step 5. Evaluate the position statically
-    // At root we do this only to get reference value for child nodes
-    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)
-
-    // Step extra. Fail low loop
-    // We start with small aspiration window and in case of fail low, we research
-    // with bigger window until we are not failing low anymore.
-    while (1)
-    {
-        // Sort the moves before to (re)search
-        rml.set_non_pv_scores(pos, rml[0].pv[0], ss);
-        rml.sort();
-        moveCount = 0;
-
-        // Step 10. Loop through all moves in the root move list
-        for (rm = rml.begin(); rm != rml.end() && !StopRequest; ++rm)
-        {
-            // 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;
-            }
-
-            // Pick the next root move, and print the move and the move number to
-            // the standard output.
-            move = ss->currentMove = rm->pv[0];
-            movesSearched[moveCount++] = move;
-            isPvMove = (moveCount <= MultiPV);
-
-            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 extra. Fail high loop
-            // If move fails high, we research with bigger window until we are not failing
-            // high anymore.
-            value = -VALUE_INFINITE;
-
-            while (1)
-            {
-                // Step 13. Make the move
-                pos.do_move(move, st, ci, moveIsCheck);
-
-                // Step extra. pv search
-                // We do pv search for PV moves and when failing high
-                if (isPvMove || value > alpha)
-                {
-                    // 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
-                        && !dangerous
-                        && !captureOrPromotion
-                        && !move_is_castle(move))
-                    {
-                        ss->reduction = reduction<PV>(depth, moveCount - MultiPV + 1);
-                        if (ss->reduction)
-                        {
-                            assert(newDepth-ss->reduction >= ONE_PLY);
-
-                            // Reduced depth non-pv search using alpha as upperbound
-                            value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth-ss->reduction, 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);
-
-                // Can we exit fail high loop ?
-                if (StopRequest || value < beta)
-                    break;
-
-                // We are failing high and going to do a research. It's important to update
-                // the score before research in case we run out of time while researching.
-                ss->bestMove = move;
-                rm->pv_score = value;
-                rm->extract_pv_from_tt(pos);
-
-                // Update killers and history only for non capture moves that fails high
-                if (!pos.move_is_capture_or_promotion(move))
-                {
-                    update_history(pos, move, depth, movesSearched, moveCount);
-                    update_killers(move, ss->killers);
-                }
-
-                // Inform GUI that PV has changed
-                cout << rm->pv_info_to_uci(pos, alpha, beta) << endl;
-
-                // Prepare for a research after a fail high, each time with a wider window
-                beta = Min(beta + AspirationDelta * (1 << researchCountFH), VALUE_INFINITE);
-                researchCountFH++;
-
-            } // End of fail high loop
-
-            // Finished searching the move. If AbortSearch 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;
-
-            assert(value >= -VALUE_INFINITE && value <= VALUE_INFINITE);
-            assert(value < beta);
-
-            // 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 = value;
-                }
-                else // Set alpha equal to minimum score among the PV lines
-                    alpha = rml[Min(moveCount, MultiPV) - 1].pv_score; // FIXME why moveCount?
-
-            } // PV move or new best move
-
-            assert(alpha >= oldAlpha);
-
-            AspirationFailLow = (alpha == oldAlpha);
-
-            if (AspirationFailLow && StopOnPonderhit)
-                StopOnPonderhit = false;
-
-        } // Root moves loop
-
-        // Can we exit fail low loop ?
-        if (StopRequest || !AspirationFailLow)
-            break;
-
-        // Prepare for a research after a fail low, each time with a wider window
-        oldAlpha = alpha = Max(alpha - AspirationDelta * (1 << researchCountFL), -VALUE_INFINITE);
-        researchCountFL++;
-
-    } // Fail low loop
-
-    // Sort the moves before to return
-    rml.sort();
-
-    // 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);
-
-    return alpha;
+    *ponderMove = Rml[0].pv[1];
+    return Rml[0].pv[0];
   }
 
 
@@ -937,16 +762,17 @@ namespace {
   // all this work again. We also don't need to store anything to the hash table
   // here: This is taken care of after we return from the split point.
 
-  template <NodeType PvNode, bool SpNode>
+  template <NodeType PvNode, bool SpNode, bool Root>
   Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) {
 
     assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
     assert(beta > alpha && beta <= VALUE_INFINITE);
     assert(PvNode || alpha == beta - 1);
-    assert(ply > 0 && ply < PLY_MAX);
+    assert((Root || ply > 0) && ply < PLY_MAX);
     assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
 
     Move movesSearched[MOVES_MAX];
+    int64_t nodes;
     StateInfo st;
     const TTEntry *tte;
     Key posKey;
@@ -955,11 +781,12 @@ namespace {
     ValueType vt;
     Value bestValue, value, oldAlpha;
     Value refinedValue, nullValue, futilityBase, futilityValueScaled; // Non-PV specific
-    bool isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous;
+    bool isPvMove, isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous;
     bool mateThreat = false;
     int moveCount = 0;
     int threadID = pos.thread();
     SplitPoint* sp = NULL;
+
     refinedValue = bestValue = value = -VALUE_INFINITE;
     oldAlpha = alpha;
     isCheck = pos.is_check();
@@ -973,30 +800,35 @@ namespace {
         mateThreat = sp->mateThreat;
         goto split_point_start;
     }
+    else if (Root)
+        bestValue = alpha;
     else {} // Hack to fix icc's "statement is unreachable" warning
 
     // 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 (threadID == 0 && ++NodesSincePoll > NodesBetweenPolls)
+    if (!Root)
     {
-        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;
+        if (threadID == 0 && ++NodesSincePoll > NodesBetweenPolls)
+        {
+            NodesSincePoll = 0;
+            poll(pos);
+        }
 
-    // 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 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;
+    }
 
     // Step 4. Transposition table lookup
 
@@ -1041,7 +873,8 @@ namespace {
     }
 
     // Save gain for the parent non-capture move
-    update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
+    if (!Root)
+        update_gains(pos, (ss-1)->currentMove, (ss-1)->eval, ss->eval);
 
     // Step 6. Razoring (is omitted in PV nodes)
     if (   !PvNode
@@ -1134,7 +967,8 @@ namespace {
     }
 
     // Step 9. Internal iterative deepening
-    if (    depth >= IIDDepth[PvNode]
+    if (   !Root
+        &&  depth >= IIDDepth[PvNode]
         &&  ttMove == MOVE_NONE
         && (PvNode || (!isCheck && ss->eval >= beta - IIDMargin)))
     {
@@ -1149,20 +983,19 @@ namespace {
     }
 
     // Expensive mate threat detection (only for PV nodes)
-    if (PvNode)
+    if (PvNode && !Root) // FIXME
         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 =  !SpNode
+    singularExtensionNode =   !Root
+                           && !SpNode
                            && depth >= SingularExtensionDepth[PvNode]
                            && tte
                            && tte->move()
@@ -1193,6 +1026,30 @@ split_point_start: // At split points actual search starts from here
       else
           movesSearched[moveCount++] = move;
 
+      if (Root)
+      {
+          // This is used by time management
+          FirstRootMove = (moveCount == 1);
+
+          // 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;
+      }
+
+      isPvMove = (PvNode && moveCount <= (Root ? MultiPV : 1));
       moveIsCheck = pos.move_is_check(move, ci);
       captureOrPromotion = pos.move_is_capture_or_promotion(move);
 
@@ -1225,7 +1082,7 @@ split_point_start: // At split points actual search starts from here
 
       // Update current move (this must be done after singular extension search)
       ss->currentMove = move;
-      newDepth = depth - ONE_PLY + ext;
+      newDepth = depth - (!Root ? ONE_PLY : DEPTH_ZERO) + ext;
 
       // Step 12. Futility pruning (is omitted in PV nodes)
       if (   !PvNode
@@ -1284,8 +1141,14 @@ split_point_start: // At split points actual search starts from here
 
       // Step extra. pv search (only in PV nodes)
       // The first move in list is the expected PV
-      if (PvNode && moveCount == 1)
+      if (isPvMove)
+      {
+          // Aspiration window is disabled in multi-pv case
+          if (Root && MultiPV > 1)
+              alpha = -VALUE_INFINITE;
+
           value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, ply+1);
+      }
       else
       {
           // Step 14. Reduced depth search
@@ -1299,8 +1162,8 @@ split_point_start: // At split points actual search starts from here
               &&  ss->killers[0] != move
               &&  ss->killers[1] != move)
           {
-              ss->reduction = reduction<PvNode>(depth, moveCount);
-
+              ss->reduction = Root ? reduction<PvNode>(depth, moveCount - MultiPV + 1)
+                                   : reduction<PvNode>(depth, moveCount);
               if (ss->reduction)
               {
                   alpha = SpNode ? sp->alpha : alpha;
@@ -1321,7 +1184,7 @@ split_point_start: // At split points actual search starts from here
               // Step extra. pv search (only in PV nodes)
               // Search only for possible new PV nodes, if instead value >= beta then
               // parent node fails low with value <= alpha and tries another move.
-              if (PvNode && value > alpha && value < beta)
+              if (PvNode && value > alpha && (Root || value < beta))
                   value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, ply+1);
           }
       }
@@ -1339,7 +1202,7 @@ split_point_start: // At split points actual search starts from here
           alpha = sp->alpha;
       }
 
-      if (value > bestValue && !(SpNode && ThreadsMgr.cutoff_at_splitpoint(threadID)))
+      if (!Root && value > bestValue && !(SpNode && ThreadsMgr.cutoff_at_splitpoint(threadID)))
       {
           bestValue = value;
 
@@ -1368,17 +1231,68 @@ split_point_start: // At split points actual search starts from here
           }
       }
 
+      if (Root)
+      {
+          // 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
+          mp.rm->nodes += pos.nodes_searched() - nodes;
+
+          // Step 17. Check for new best move
+          if (!isPvMove && value <= alpha)
+              mp.rm->pv_score = -VALUE_INFINITE;
+          else
+          {
+              // PV move or new best move!
+
+              // Update PV
+              ss->bestMove = move;
+              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)
+                  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);
+
+              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?
+
+          } // PV move or new best move
+      }
+
       // Step 18. Check for split
-      if (   !SpNode
+      if (   !Root
+          && !SpNode
           && depth >= ThreadsMgr.min_split_depth()
           && ThreadsMgr.active_threads() > 1
           && 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);
+                                      threatMove, mateThreat, moveCount, (MovePicker*)&mp, PvNode);
     }
 
     // Step 19. Check for mate and stalemate
@@ -1905,8 +1819,9 @@ split_point_start: // At split points actual search starts from here
   void update_history(const Position& pos, Move move, Depth depth,
                       Move movesSearched[], int moveCount) {
     Move m;
+    Value bonus = Value(int(depth) * int(depth));
 
-    H.success(pos.piece_on(move_from(move)), move_to(move), depth);
+    H.update(pos.piece_on(move_from(move)), move_to(move), bonus);
 
     for (int i = 0; i < moveCount - 1; i++)
     {
@@ -1915,7 +1830,7 @@ split_point_start: // At split points actual search starts from here
         assert(m != move);
 
         if (!pos.move_is_capture_or_promotion(m))
-            H.failure(pos.piece_on(move_from(m)), move_to(m), depth);
+            H.update(pos.piece_on(move_from(m)), move_to(m), -bonus);
     }
   }
 
@@ -1943,7 +1858,7 @@ split_point_start: // At split points actual search starts from here
         && after != VALUE_NONE
         && pos.captured_piece_type() == PIECE_TYPE_NONE
         && !move_is_special(m))
-        H.set_gain(pos.piece_on(move_to(m)), move_to(m), -(before + after));
+        H.update_gain(pos.piece_on(move_to(m)), move_to(m), -(before + after));
   }
 
 
@@ -2013,7 +1928,7 @@ split_point_start: // At split points actual search starts from here
     int t = current_search_time();
 
     //  Poll for input
-    if (data_available())
+    if (input_available())
     {
         // We are line oriented, don't read single chars
         std::string command;
@@ -2223,9 +2138,9 @@ split_point_start: // At split points actual search starts from here
             ss->sp = tsp;
 
             if (tsp->pvNode)
-                search<PV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
+                search<PV, true, false>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
             else
-                search<NonPV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
+                search<NonPV, true, false>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
 
             assert(threads[threadID].state == THREAD_SEARCHING);
 
@@ -2630,7 +2545,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(const 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;
@@ -2638,7 +2553,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)
@@ -2653,13 +2568,13 @@ 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];
@@ -2669,6 +2584,8 @@ split_point_start: // At split points actual search starts from here
     // Initialize search stack
     init_ss_array(ss, PLY_MAX_PLUS_2);
     ss[0].eval = ss[0].evalMargin = VALUE_NONE;
+    bestMoveChanges = 0;
+    clear();
 
     // Generate all legal moves
     MoveStack* last = generate<MV_LEGAL>(pos, mlist);
@@ -2717,35 +2634,4 @@ split_point_start: // At split points actual search starts from here
               }
   }
 
-  // Overload operator << to make it easier to print moves in coordinate notation
-  // (g1f3, a7a8q, etc.). The only special case is castling moves, where we
-  // print in the e1g1 notation in normal chess mode, and in e1h1 notation in
-  // Chess960 mode.
-
-  std::ostream& operator<<(std::ostream& os, Move m) {
-
-    Square from = move_from(m);
-    Square to = move_to(m);
-    bool chess960 = (os.iword(0) != 0); // See set960()
-
-    if (m == MOVE_NONE)
-        return os << "(none)";
-
-    if (m == MOVE_NULL)
-        return os << "0000";
-
-    if (move_is_short_castle(m) && !chess960)
-        return os << (from == SQ_E1 ? "e1g1" : "e8g8");
-
-    if (move_is_long_castle(m) && !chess960)
-        return os << (from == SQ_E1 ? "e1c1" : "e8c8");
-
-    os << square_to_string(from) << square_to_string(to);
-
-    if (move_is_promotion(m))
-        os << char(tolower(piece_type_to_char(move_promotion_piece(m))));
-
-    return os;
-  }
-
 } // namespace