]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Rewrite pv_info_xxx() signatures
[stockfish] / src / search.cpp
index 4b189933489205394ed84f85cd0333361e408ec7..df09007f1538f8f15134e6df34edbc8dafacb93e 100644 (file)
@@ -145,8 +145,8 @@ namespace {
   Value refine_eval(const TTEntry* tte, Value ttValue, Value defaultEval);
   Move do_skill_level();
   string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
-  void pv_info_to_log(Position& pos, int depth, Value score, int time, Move pv[]);
-  void pv_info_to_uci(const Position& pos, int depth, Value alpha, Value beta);
+  string pretty_pv(Position& pos, int depth, Value score, int time, Move pv[]);
+  string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
 
   // MovePickerExt class template extends MovePicker and allows to choose at
   // compile time the proper moves source according to the type of node. In the
@@ -171,12 +171,16 @@ namespace {
   // 'dangerous' moves so that we avoid to prune it.
   FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) {
 
-    // Test for a passed pawn move
+    // Castle move?
+    if (type_of(m) == CASTLE)
+        return true;
+
+    // Passed pawn move?
     if (   type_of(pos.piece_moved(m)) == PAWN
         && pos.pawn_is_passed(pos.side_to_move(), to_sq(m)))
         return true;
 
-    // Test for a capture that triggers a pawn endgame
+    // Entering a pawn endgame?
     if (    captureOrPromotion
         &&  type_of(pos.piece_on(to_sq(m))) != PAWN
         &&  type_of(m) == NORMAL
@@ -423,7 +427,7 @@ namespace {
                 // Send full PV info to GUI if we are going to leave the loop or
                 // if we have a fail high/low and we are deep in the search.
                 if ((bestValue > alpha && bestValue < beta) || SearchTime.elapsed() > 2000)
-                    pv_info_to_uci(pos, depth, alpha, beta);
+                    cout << uci_pv(pos, depth, alpha, beta) << endl;
 
                 // In case of failing high/low increase aspiration window and
                 // research, otherwise exit the fail high/low loop.
@@ -453,7 +457,11 @@ namespace {
             skillBest = do_skill_level();
 
         if (!Signals.stop && Options["Use Search Log"])
-             pv_info_to_log(pos, depth, bestValue, SearchTime.elapsed(), &RootMoves[0].pv[0]);
+        {
+            Log log(Options["Search Log Filename"]);
+            log << pretty_pv(pos, depth, bestValue, SearchTime.elapsed(), &RootMoves[0].pv[0])
+                << endl;
+        }
 
         // Filter out startup noise when monitoring best move stability
         if (depth > 2 && BestMoveChanges)
@@ -874,19 +882,18 @@ split_point_start: // At split points actual search starts from here
       if (    singularExtensionNode
           && !ext
           &&  move == ttMove
-          &&  pos.pl_move_is_legal(move, ci.pinned))
+          &&  pos.pl_move_is_legal(move, ci.pinned)
+          &&  abs(ttValue) < VALUE_KNOWN_WIN)
       {
-          if (abs(ttValue) < VALUE_KNOWN_WIN)
-          {
-              Value rBeta = ttValue - int(depth);
-              ss->excludedMove = move;
-              ss->skipNullMove = true;
-              value = search<NonPV>(pos, ss, rBeta - 1, rBeta, depth / 2);
-              ss->skipNullMove = false;
-              ss->excludedMove = MOVE_NONE;
-              if (value < rBeta)
-                  ext = ONE_PLY;
-          }
+          Value rBeta = ttValue - int(depth);
+          ss->excludedMove = move;
+          ss->skipNullMove = true;
+          value = search<NonPV>(pos, ss, rBeta - 1, rBeta, depth / 2);
+          ss->skipNullMove = false;
+          ss->excludedMove = MOVE_NONE;
+
+          if (value < rBeta)
+              ext = ONE_PLY;
       }
 
       // Update current move (this must be done after singular extension search)
@@ -898,7 +905,6 @@ split_point_start: // At split points actual search starts from here
           && !inCheck
           && !dangerous
           &&  move != ttMove
-          &&  type_of(move) != CASTLE
           && (bestValue > VALUE_MATED_IN_MAX_PLY || bestValue == -VALUE_INFINITE))
       {
           // Move count based pruning
@@ -957,7 +963,6 @@ split_point_start: // At split points actual search starts from here
           && !isPvMove
           && !captureOrPromotion
           && !dangerous
-          &&  type_of(move) != CASTLE
           &&  ss->killers[0] != move
           &&  ss->killers[1] != move)
       {
@@ -1529,12 +1534,13 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // pv_info_to_uci() sends search info to GUI. UCI protocol requires to send all
-  // the PV lines also if are still to be searched and so refer to the previous
-  // search score.
+  // uci_pv() formats PV information according to UCI protocol. UCI requires
+  // to send all the PV lines also if are still to be searched and so refer to
+  // the previous search score.
 
-  void pv_info_to_uci(const Position& pos, int depth, Value alpha, Value beta) {
+  string uci_pv(const Position& pos, int depth, Value alpha, Value beta) {
 
+    std::stringstream s;
     int t = SearchTime.elapsed();
     int selDepth = 0;
 
@@ -1551,26 +1557,30 @@ split_point_start: // At split points actual search starts from here
 
         int d = (updated ? depth : depth - 1);
         Value v = (updated ? RootMoves[i].score : RootMoves[i].prevScore);
-        std::stringstream s;
 
-        for (int j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++)
-            s <<  " " << move_to_uci(RootMoves[i].pv[j], Chess960);
+        if (s.rdbuf()->in_avail())
+            s << "\n";
 
-        cout << "info depth " << d
-             << " seldepth " << selDepth
-             << " score " << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v))
-             << " nodes " << pos.nodes_searched()
-             << " nps " << (t > 0 ? pos.nodes_searched() * 1000 / t : 0)
-             << " time " << t
-             << " multipv " << i + 1
-             << " pv" << s.str() << endl;
+        s << "info depth " << d
+          << " seldepth " << selDepth
+          << " score " << (i == PVIdx ? score_to_uci(v, alpha, beta) : score_to_uci(v))
+          << " nodes " << pos.nodes_searched()
+          << " nps " << (t > 0 ? pos.nodes_searched() * 1000 / t : 0)
+          << " time " << t
+          << " multipv " << i + 1
+          << " pv";
+
+        for (size_t j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++)
+            s <<  " " << move_to_uci(RootMoves[i].pv[j], Chess960);
     }
+
+    return s.str();
   }
 
 
-  // pv_info_to_log() writes human-readable search information to the log file
-  // (which is created when the UCI parameter "Use Search Log" is "true"). It
-  // uses the two below helpers to pretty format time and score respectively.
+  // pretty_pv() formats human-readable search information, typically to be
+  // appended to the search log file. It uses the two helpers below to pretty
+  // format time and score respectively.
 
   string time_to_string(int millisecs) {
 
@@ -1597,8 +1607,10 @@ split_point_start: // At split points actual search starts from here
 
     if (v >= VALUE_MATE_IN_MAX_PLY)
         s << "#" << (VALUE_MATE - v + 1) / 2;
+
     else if (v <= VALUE_MATED_IN_MAX_PLY)
         s << "-#" << (VALUE_MATE + v) / 2;
+
     else
         s << std::setprecision(2) << std::fixed << std::showpos
           << float(v) / PawnValueMidgame;
@@ -1606,7 +1618,7 @@ split_point_start: // At split points actual search starts from here
     return s.str();
   }
 
-  void pv_info_to_log(Position& pos, int depth, Value value, int time, Move pv[]) {
+  string pretty_pv(Position& pos, int depth, Value value, int time, Move pv[]) {
 
     const int64_t K = 1000;
     const int64_t M = 1000000;
@@ -1652,8 +1664,7 @@ split_point_start: // At split points actual search starts from here
     while (m != pv)
         pos.undo_move(*--m);
 
-    Log l(Options["Search Log Filename"]);
-    l << s.str() << endl;
+    return s.str();
   }