]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Score root move list during first iteration
[stockfish] / src / search.cpp
index 6d05405b6f79c9ad002824bbafd0777b132f000b..915e1af25d69ccee4e5faead5f68cf58b14ecd96 100644 (file)
@@ -209,10 +209,6 @@ namespace {
   // Minimum depth for use of singular extension
   const Depth SingularExtensionDepth[2] = { 8 * ONE_PLY /* non-PV */, 6 * ONE_PLY /* PV */};
 
-  // If the TT move is at least SingularExtensionMargin better than the
-  // remaining ones we will extend it.
-  const Value SingularExtensionMargin = Value(0x20);
-
   // Step 12. Futility pruning
 
   // Futility margin for quiescence search
@@ -302,11 +298,10 @@ 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);
+  std::string speed_to_uci(int64_t nodes);
   void poll(const Position& pos);
   void wait_for_stop_or_ponderhit();
 
@@ -558,14 +553,14 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   Move bestMove = id_loop(pos, searchMoves, &ponderMove);
 
   // Print final search statistics
-  cout << "info nodes " << pos.nodes_searched()
-       << " nps " << nps(pos)
-       << " time " << current_search_time() << endl;
+  cout << "info" << speed_to_uci(pos.nodes_searched()) << endl;
 
   if (UseLogFile)
   {
+      int t = current_search_time();
+
       LogFile << "Nodes: "          << pos.nodes_searched()
-              << "\nNodes/second: " << nps(pos)
+              << "\nNodes/second: " << (t > 0 ? int(pos.nodes_searched() * 1000 / t) : 0)
               << "\nBest move: "    << move_to_san(pos, bestMove);
 
       StateInfo st;
@@ -605,7 +600,7 @@ namespace {
     Value value, alpha, beta;
     Move bestMove, easyMove;
 
-    // Moves to search are verified, scored and sorted
+    // Moves to search are verified and copied
     Rml.init(pos, searchMoves);
 
     // Initialize FIXME move before Rml.init()
@@ -627,11 +622,6 @@ namespace {
         return MOVE_NONE;
     }
 
-    // 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];
-
     // Iterative deepening loop
     while (++depth <= PLY_MAX && (!MaxDepth || depth <= MaxDepth) && !StopRequest)
     {
@@ -700,8 +690,10 @@ namespace {
         if (UseLogFile)
             LogFile << pretty_pv(pos, depth, value, current_search_time(), Rml[0].pv) << endl;
 
-        // Drop the easy move if differs from the new best move
-        if (bestMove != easyMove)
+        // Init easyMove after first iteration or drop if differs from the best move
+        if (depth == 1 && (Rml.size() == 1 || Rml[0].pv_score > Rml[1].pv_score + EasyMoveMargin))
+            easyMove = bestMove;
+        else if (bestMove != easyMove)
             easyMove = MOVE_NONE;
 
         if (UseTimeManagement && !StopRequest)
@@ -1028,9 +1020,7 @@ split_point_start: // At split points actual search starts from here
           if (SendSearchedNodes)
           {
               SendSearchedNodes = false;
-              cout << "info nodes " << nodes
-                   << " nps " << nps(pos)
-                   << " time " << current_search_time() << endl;
+              cout << "info" << speed_to_uci(pos.nodes_searched()) << endl;
           }
 
           if (current_search_time() >= 1000)
@@ -1038,7 +1028,9 @@ split_point_start: // At split points actual search starts from here
                    << " currmovenumber " << moveCount << endl;
       }
 
-      isPvMove = (PvNode && moveCount <= (Root ? MultiPV : 1));
+      // At Root and at first iteration do a PV search on all the moves
+      // to score root moves. Otherwise only the first one is the PV.
+      isPvMove = (PvNode && moveCount <= (Root ? MultiPV + 1000 * (depth <= ONE_PLY) : 1));
       moveIsCheck = pos.move_is_check(move, ci);
       captureOrPromotion = pos.move_is_capture_or_promotion(move);
 
@@ -1057,7 +1049,7 @@ split_point_start: // At split points actual search starts from here
 
           if (abs(ttValue) < VALUE_KNOWN_WIN)
           {
-              Value b = ttValue - SingularExtensionMargin;
+              Value b = ttValue - depth;
               ss->excludedMove = move;
               ss->skipNullMove = true;
               Value v = search<NonPV>(pos, ss, b - 1, b, depth / 2, ply);
@@ -1433,6 +1425,12 @@ split_point_start: // At split points actual search starts from here
                   bestValue = futilityValue;
               continue;
           }
+
+          // Prune moves with negative or equal SEE
+          if (   futilityBase < beta
+              && depth < DEPTH_ZERO
+              && pos.see(move) <= 0)
+              continue;
       }
 
       // Detect non-capture evasions that are candidate to be pruned
@@ -1501,26 +1499,6 @@ 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.
@@ -1858,6 +1836,14 @@ split_point_start: // At split points actual search starts from here
         H.update_gain(pos.piece_on(move_to(m)), move_to(m), -(before + after));
   }
 
+  // current_search_time() returns the number of milliseconds which have passed
+  // since the beginning of the current search.
+
+  int current_search_time() {
+
+    return get_system_time() - SearchStartTime;
+  }
+
 
   // value_to_uci() converts a value to a string suitable for use with the UCI
   // protocol specifications:
@@ -1879,21 +1865,19 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // current_search_time() returns the number of milliseconds which have passed
-  // since the beginning of the current search.
-
-  int current_search_time() {
-
-    return get_system_time() - SearchStartTime;
-  }
+  // speed_to_uci() returns a string with time stats of current search suitable
+  // to be sent to UCI gui.
 
+  std::string speed_to_uci(int64_t nodes) {
 
-  // nps() computes the current nodes/second count
+    std::stringstream s;
+    int t = current_search_time();
 
-  int nps(const Position& pos) {
+    s << " nodes " << nodes
+      << " nps "   << (t > 0 ? int(nodes * 1000 / t) : 0)
+      << " time "  << t;
 
-    int t = current_search_time();
-    return (t > 0 ? int((pos.nodes_searched() * 1000) / t) : 0);
+    return s.str();
   }
 
 
@@ -2538,9 +2522,7 @@ split_point_start: // At split points actual search starts from here
       << " multipv " << pvLine + 1
       << " score " << value_to_uci(pv_score)
       << (pv_score >= beta ? " lowerbound" : pv_score <= alpha ? " upperbound" : "")
-      << " time "  << current_search_time()
-      << " nodes " << pos.nodes_searched()
-      << " nps "   << nps(pos)
+      << speed_to_uci(pos.nodes_searched())
       << " pv "    << l.str();
 
     return s.str();
@@ -2555,11 +2537,8 @@ split_point_start: // At split points actual search starts from here
     clear();
     bestMoveChanges = 0;
 
-    // Generate all legal moves and score them
+    // Generate all legal moves and add them to RootMoveList
     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++)
     {
         // If we have a searchMoves[] list then verify cur->move
@@ -2572,10 +2551,9 @@ split_point_start: // At split points actual search starts from here
         RootMove rm;
         rm.pv[0] = cur->move;
         rm.pv[1] = MOVE_NONE;
-        rm.pv_score = Value(cur->score);
+        rm.pv_score = -VALUE_INFINITE;
         push_back(rm);
     }
-    sort();
   }
 
 } // namespace