]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Sort root moves moves in MovePickerExt
[stockfish] / src / search.cpp
index 91b4b20c79e6330e7966d778f96fd9245de58021..2d390dd151c489f0af31ea18e1437b154f5a8ab5 100644 (file)
@@ -146,8 +146,6 @@ namespace {
     typedef std::vector<RootMove> Base;
 
     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); }
 
@@ -327,11 +325,30 @@ namespace {
   // 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> {
+  // In Root nodes use RootMoveList Rml as source. Score and sort the moves before to search them.
+  template<> struct MovePickerExt<false, true> : private MovePicker {
+
+      MovePickerExt(const Position& p, Move, Depth, const History& h, SearchStack* ss, Value beta)
+                  : MovePicker(p, Rml[0].pv[0], ONE_PLY, h, ss, beta), firstCall(true) { // FIXME use depth
 
-      MovePickerExt(const Position&, Move, Depth, const History&, SearchStack*, Value)
-                  : rm(Rml.begin()), 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() {
 
@@ -594,39 +611,36 @@ namespace {
   Move id_loop(Position& pos, Move searchMoves[], Move* ponderMove) {
 
     SearchStack ss[PLY_MAX_PLUS_2];
-
-    Depth depth;
-    Move EasyMove = MOVE_NONE;
-    Value value, alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
-    int researchCountFL, researchCountFH;
-
-    int iteration;
+    Value bestValues[PLY_MAX_PLUS_2];
     int bestMoveChanges[PLY_MAX_PLUS_2];
-    Value values[PLY_MAX_PLUS_2];
-    int aspirationDelta = 0;
+    int iteration, researchCountFL, researchCountFH, aspirationDelta;
+    Value value, alpha, beta;
+    Depth depth;
+    Move EasyMove;
 
     // Moves to search are verified, scored and sorted
     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)
     {
-        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);
-    values[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, ONE_PLY, alpha, beta) << endl;
@@ -637,58 +651,51 @@ namespace {
         EasyMove = Rml[0].pv[0];
 
     // Iterative deepening loop
-    while (iteration < PLY_MAX)
+    while (++iteration <= PLY_MAX && (!MaxDepth || iteration <= MaxDepth) && !StopRequest)
     {
-        // Initialize iteration
-        iteration++;
-        Rml.bestMoveChanges = 0;
-
         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(values[iteration - 1]) < VALUE_KNOWN_WIN)
+        if (MultiPV == 1 && iteration >= 6 && abs(bestValues[iteration - 1]) < VALUE_KNOWN_WIN)
         {
-            int prevDelta1 = values[iteration - 1] - values[iteration - 2];
-            int prevDelta2 = values[iteration - 2] - values[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
 
-            alpha = Max(values[iteration - 1] - aspirationDelta, -VALUE_INFINITE);
-            beta  = Min(values[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.
         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
+            // Sort root 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);
 
-            bestMoveChanges[iteration] = Rml.bestMoveChanges;
-
+            // Value cannot be trusted. Break out immediately!
             if (StopRequest)
-                break;
+                break; // FIXME move to 'while' condition
 
             assert(value >= alpha);
 
+            bestMoveChanges[iteration] = Rml.bestMoveChanges; // FIXME move outside fail high/low loop
+
+            // 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);
                 researchCountFH++;
             }
@@ -697,7 +704,6 @@ 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);
                 researchCountFL++;
             }
@@ -705,17 +711,14 @@ namespace {
                 break;
         }
 
-        if (StopRequest)
-            break; // Value cannot be trusted. Break out immediately!
-
         //Save info about search result
-        values[iteration] = value;
+        bestValues[iteration] = value;
 
         // Drop the easy move if differs from the new best move
         if (Rml[0].pv[0] != EasyMove)
             EasyMove = MOVE_NONE;
 
-        if (UseTimeManagement)
+        if (UseTimeManagement && !StopRequest)
         {
             // Time to stop?
             bool noMoreTime = false;
@@ -727,8 +730,8 @@ namespace {
 
             // Stop search early when the last two iterations returned a mate score
             if (   iteration >= 6
-                && abs(values[iteration]) >= abs(VALUE_MATE) - 100
-                && abs(values[iteration-1]) >= abs(VALUE_MATE) - 100)
+                && 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
@@ -758,9 +761,6 @@ namespace {
                     break;
             }
         }
-
-        if (MaxDepth && iteration >= MaxDepth)
-            break;
     }
 
     *ponderMove = Rml[0].pv[1];
@@ -813,13 +813,14 @@ 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 (!Root) // FIXME remove
     {
         if (threadID == 0 && ++NodesSincePoll > NodesBetweenPolls)
         {
@@ -1013,9 +1014,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)
-        bestValue = alpha;
-
     if (SpNode)
     {
         lock_grab(&(sp->lock));
@@ -1247,6 +1245,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
@@ -1283,15 +1285,12 @@ split_point_start: // At split points actual search starts from here
               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
       }
@@ -2628,24 +2627,4 @@ split_point_start: // At split points actual search starts from here
     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