Reformat sending of PV information
authorMarco Costalba <mcostalba@gmail.com>
Wed, 14 Dec 2011 08:21:00 +0000 (09:21 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Wed, 14 Dec 2011 18:22:22 +0000 (19:22 +0100)
Introduce pv_info_to_log() and pv_info_to_uci() and
greatly cleanup this stuff.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/search.cpp

index b160145ef4baafae8c8640a52cb60324ad960eff..679ebbbd1e457a8c111bfdde2aa3b75ed1202af6 100644 (file)
@@ -174,10 +174,8 @@ namespace {
   void do_skill_level(Move* best, Move* ponder);
   int elapsed_time(bool reset = false);
   string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
-  string speed_to_uci(int64_t nodes);
-  string pv_to_uci(const Move pv[], int pvNum, bool chess960);
-  string pretty_pv(Position& pos, int depth, Value score, int time, Move pv[]);
-  string depth_to_uci(Depth depth);
+  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);
 
   // MovePickerExt class template extends MovePicker and allows to choose at
   // compile time the proper moves source according to the type of node. In the
@@ -448,7 +446,7 @@ namespace {
     // Handle special case of searching on a mate/stalemate position
     if (RootMoves.empty())
     {
-        cout << "info" << depth_to_uci(DEPTH_ZERO)
+        cout << "info depth 0"
              << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW, alpha, beta) << endl;
 
         return MOVE_NONE;
@@ -466,7 +464,7 @@ namespace {
         // MultiPV loop. We perform a full root search for each PV line
         for (MultiPVIdx = 0; MultiPVIdx < std::min(MultiPV, RootMoves.size()); MultiPVIdx++)
         {
-            // Calculate dynamic aspiration window based on previous iteration
+            // Aspiration window
             if (depth >= 5 && abs(RootMoves[MultiPVIdx].prevScore) < VALUE_KNOWN_WIN)
             {
                 delta = Value(16);
@@ -513,27 +511,9 @@ namespace {
                     break;
 
                 // 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. UCI
-                // protocol requires to send all the PV lines also if are still
-                // to be searched and so refer to the previous search's score.
+                // if we have a fail high/low and we are deep in the search.
                 if ((bestValue > alpha && bestValue < beta) || elapsed_time() > 2000)
-                    for (size_t i = 0; i < std::min(UCIMultiPV, RootMoves.size()); i++)
-                    {
-                        bool updated = (i <= MultiPVIdx);
-
-                        if (depth == 1 && !updated)
-                            continue;
-
-                        Depth d = (updated ? depth : depth - 1) * ONE_PLY;
-                        Value s = (updated ? RootMoves[i].score : RootMoves[i].prevScore);
-
-                        cout << "info"
-                             << depth_to_uci(d)
-                             << (i == MultiPVIdx ? score_to_uci(s, alpha, beta) : score_to_uci(s))
-                             << speed_to_uci(pos.nodes_searched())
-                             << pv_to_uci(&RootMoves[i].pv[0], i + 1, pos.is_chess960())
-                             << endl;
-                    }
+                    pv_info_to_uci(pos, depth, alpha, beta);
 
                 // In case of failing high/low increase aspiration window and
                 // research, otherwise exit the fail high/low loop.
@@ -567,10 +547,7 @@ namespace {
             do_skill_level(&skillBest, &skillPonder);
 
         if (Options["Use Search Log"].value<bool>())
-        {
-            Log log(Options["Search Log Filename"].value<string>());
-            log << pretty_pv(pos, depth, bestValue, elapsed_time(), &RootMoves[0].pv[0]) << endl;
-        }
+             pv_info_to_log(pos, depth, bestValue, elapsed_time(), &RootMoves[0].pv[0]);
 
         // Filter out startup noise when monitoring best move stability
         if (depth > 2 && bestMoveChanges[depth])
@@ -960,7 +937,7 @@ split_point_start: // At split points actual search starts from here
           nodes = pos.nodes_searched();
 
           if (pos.thread() == 0 && elapsed_time() > 2000)
-              cout << "info" << depth_to_uci(depth)
+              cout << "info depth " << depth / ONE_PLY
                    << " currmove " << move
                    << " currmovenumber " << moveCount + MultiPVIdx << endl;
       }
@@ -1701,61 +1678,49 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // speed_to_uci() returns a string with time stats of current search suitable
-  // to be sent to UCI gui.
+  // 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.
 
-  string speed_to_uci(int64_t nodes) {
+  void pv_info_to_uci(const Position& pos, int depth, Value alpha, Value beta) {
 
-    std::stringstream s;
     int t = elapsed_time();
-
-    s << " nodes " << nodes
-      << " nps " << (t > 0 ? int(nodes * 1000 / t) : 0)
-      << " time "  << t;
-
-    return s.str();
-  }
-
-
-  // pv_to_uci() returns a string with information on the current PV line
-  // formatted according to UCI specification.
-
-  string pv_to_uci(const Move pv[], int pvNum, bool chess960) {
-
-    std::stringstream s;
-
-    s << " multipv " << pvNum << " pv " << set960(chess960);
-
-    for ( ; *pv != MOVE_NONE; pv++)
-        s << *pv << " ";
-
-    return s.str();
-  }
-
-
-  // depth_to_uci() returns a string with information on the current depth and
-  // seldepth formatted according to UCI specification.
-
-  string depth_to_uci(Depth depth) {
-
-    std::stringstream s;
     int selDepth = 0;
 
-    // Retrieve max searched depth among threads
     for (int i = 0; i < Threads.size(); i++)
         if (Threads[i].maxPly > selDepth)
             selDepth = Threads[i].maxPly;
 
-    s << " depth " << depth / ONE_PLY << " seldepth " << selDepth;
+    for (size_t i = 0; i < std::min(UCIMultiPV, RootMoves.size()); i++)
+    {
+        bool updated = (i <= MultiPVIdx);
 
-    return s.str();
+        if (depth == 1 && !updated)
+            continue;
+
+        int d = (updated ? depth : depth - 1);
+        Value s = (updated ? RootMoves[i].score : RootMoves[i].prevScore);
+
+        cout << "info"
+             << " depth " << d
+             << " seldepth " << selDepth
+             << (i == MultiPVIdx ? score_to_uci(s, alpha, beta) : score_to_uci(s))
+             << " nodes " << pos.nodes_searched()
+             << " nps " << (t > 0 ? pos.nodes_searched() * 1000 / t : 0)
+             << " time " << t
+             << " multipv " << i + 1 << " pv";
+
+        for (int j = 0; RootMoves[i].pv[j] != MOVE_NONE; j++)
+            cout <<  " " << RootMoves[i].pv[j];
+
+        cout << endl;
+    }
   }
 
 
-  // pretty_pv() creates a human-readable string from a position and a PV. It is
-  // used to write search information to the log file (which is created when the
-  // UCI parameter "Use Search Log" is "true"). It uses the two below helper to
-  // pretty format time and score respectively.
+  // 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.
 
   string time_to_string(int millisecs) {
 
@@ -1791,7 +1756,7 @@ split_point_start: // At split points actual search starts from here
     return s.str();
   }
 
-  string pretty_pv(Position& pos, int depth, Value value, int time, Move pv[]) {
+  void pv_info_to_log(Position& pos, int depth, Value value, int time, Move pv[]) {
 
     const int64_t K = 1000;
     const int64_t M = 1000000;
@@ -1809,8 +1774,10 @@ split_point_start: // At split points actual search starts from here
 
     if (pos.nodes_searched() < M)
         s << std::setw(8) << pos.nodes_searched() / 1 << "  ";
+
     else if (pos.nodes_searched() < K * M)
         s << std::setw(7) << pos.nodes_searched() / K << "K  ";
+
     else
         s << std::setw(7) << pos.nodes_searched() / M << "M  ";
 
@@ -1833,11 +1800,11 @@ split_point_start: // At split points actual search starts from here
         pos.do_move(*m++, *st++);
     }
 
-    // Restore original position before to leave
     while (m != pv)
         pos.undo_move(*--m);
 
-    return s.str();
+    Log l(Options["Search Log Filename"].value<string>());
+    l << s.str() << endl;
   }
 
 
@@ -1932,7 +1899,7 @@ split_point_start: // At split points actual search starts from here
     Value v, m = VALUE_NONE;
     int ply = 0;
 
-    assert(pv[0] != MOVE_NONE && pos.is_pseudo_legal(pv[0]));
+    assert(pv[ply] != MOVE_NONE && pos.is_pseudo_legal(pv[ply]));
 
     do {
         k = pos.get_key();