]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Better document and reshuffle stuff in think()
[stockfish] / src / search.cpp
index fefc886424e9935116191a27c44594b7ad6d887b..8257b5bb9f33d308ef668539e75ccb4f89567f12 100644 (file)
@@ -353,15 +353,16 @@ int64_t perft(Position& pos, Depth depth) {
 
 bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
 
-  static Book book; // Define static to initialize the PRNG only once
+  static Book book; // Defined static to initialize the PRNG only once
+
+  // Save "search start" time and reset elapsed time to zero
+  elapsed_search_time(get_system_time());
 
   // Initialize global search-related variables
   StopOnPonderhit = StopRequest = QuitRequest = AspirationFailLow = false;
-  elapsed_search_time(get_system_time());
   Limits = limits;
-  TimeMgr.init(Limits, pos.startpos_ply_counter());
 
-  // Set output steram in normal or chess960 mode
+  // Set output stream mode: normal or chess960. Castling notation is different
   cout << set960(pos.is_chess960());
 
   // Look for a book move
@@ -381,16 +382,7 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
       }
   }
 
-  // Set best timer interval to avoid lagging under time pressure
-  if (TimeMgr.available_time())
-      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 8, 20)));
-  else
-      Threads.set_timer(100);
-
-  // Read UCI options
-  UCIMultiPV = Options["MultiPV"].value<int>();
-  SkillLevel = Options["Skill Level"].value<int>();
-
+  // Read UCI options: GUI could change UCI parameters during the game
   read_evaluation_uci_options(pos.side_to_move());
   Threads.read_uci_options();
 
@@ -403,19 +395,15 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
       TT.clear();
   }
 
+  UCIMultiPV = Options["MultiPV"].value<int>();
+  SkillLevel = Options["Skill Level"].value<int>();
+
   // Do we have to play with skill handicap? In this case enable MultiPV that
   // we will use behind the scenes to retrieve a set of possible moves.
   SkillLevelEnabled = (SkillLevel < 20);
   MultiPV = (SkillLevelEnabled ? std::max(UCIMultiPV, 4) : UCIMultiPV);
 
-  // Wake up needed threads and reset maxPly counter
-  for (int i = 0; i < Threads.size(); i++)
-  {
-      Threads[i].wake_up();
-      Threads[i].maxPly = 0;
-  }
-
-  // Write to log file and keep it open to be accessed during the search
+  // Write current search header to log file
   if (Options["Use Search Log"].value<bool>())
   {
       Log log(Options["Search Log Filename"].value<string>());
@@ -428,6 +416,22 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
           << endl;
   }
 
+  // Wake up needed threads and reset maxPly counter
+  for (int i = 0; i < Threads.size(); i++)
+  {
+      Threads[i].maxPly = 0;
+      Threads[i].wake_up();
+  }
+
+  // Set best timer interval to avoid lagging under time pressure. Timer is
+  // used to check for remaining available thinking time.
+   TimeMgr.init(Limits, pos.startpos_ply_counter());
+
+  if (TimeMgr.available_time())
+      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 8, 20)));
+  else
+      Threads.set_timer(100);
+
   // Start async mode to catch UCI commands sent to us while searching,
   // like "quit", "stop", etc.
   Threads.start_listener();
@@ -436,9 +440,16 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
   Move ponderMove = MOVE_NONE;
   Move bestMove = id_loop(pos, searchMoves, &ponderMove);
 
+  // From now on any UCI command will be read in-sync with Threads.getline()
+  Threads.stop_listener();
+
+  // Stop timer, no need to check for available time any more
   Threads.set_timer(0);
 
-  // Write final search statistics and close log file
+  // This makes all the slave threads to go to sleep, if not already sleeping
+  Threads.set_size(1);
+
+  // Write current search final statistics to log file
   if (Options["Use Search Log"].value<bool>())
   {
       int e = elapsed_search_time();
@@ -454,15 +465,9 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
       pos.undo_move(bestMove); // Return from think() with unchanged position
   }
 
-  // This makes all the threads to go to sleep
-  Threads.set_size(1);
-
-  // From now on any UCI command will be read in-sync with Threads.getline()
-  Threads.stop_listener();
-
-  // If we are pondering or in infinite search, we shouldn't print the
-  // best move before we are told to do so.
-  if (!StopRequest && (Limits.ponder || Limits.infinite))
+  // If we are pondering or in infinite search, we shouldn't print the best move
+  // before we are told to do so.
+  if (Limits.ponder || Limits.infinite)
       wait_for_stop_or_ponderhit();
 
   // Could be MOVE_NONE when searching on a stalemate position
@@ -1778,6 +1783,7 @@ split_point_start: // At split points actual search starts from here
     return s.str();
   }
 
+
   // pv_to_uci() returns a string with information on the current PV line
   // formatted according to UCI specification.
 
@@ -1793,6 +1799,7 @@ split_point_start: // At split points actual search starts from here
     return s.str();
   }
 
+
   // depth_to_uci() returns a string with information on the current depth and
   // seldepth formatted according to UCI specification.
 
@@ -1843,6 +1850,7 @@ split_point_start: // At split points actual search starts from here
     return s.str();
   }
 
+
   // 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").
@@ -1900,24 +1908,25 @@ split_point_start: // At split points actual search starts from here
   // while the program is pondering. The point is to work around a wrinkle in
   // the UCI protocol: When pondering, the engine is not allowed to give a
   // "bestmove" before the GUI sends it a "stop" or "ponderhit" command.
-  // We simply wait here until one of these commands is sent, and return,
-  // after which the bestmove and pondermove will be printed.
+  // We simply wait here until one of these commands (that raise StopRequest) is
+  // sent, and return, after which the bestmove and pondermove will be printed.
 
   void wait_for_stop_or_ponderhit() {
 
     string cmd;
+    StopOnPonderhit = true;
 
-    // Wait for a command from stdin
-    while (cmd != "ponderhit" && cmd != "stop" && cmd != "quit")
+    while (!StopRequest)
+    {
         Threads.getline(cmd);
-
-    if (cmd == "quit")
-        QuitRequest = true;
+        do_uci_async_cmd(cmd);
+    }
   }
 
 
   // When playing with strength handicap choose best move among the MultiPV set
   // using a statistical rule dependent on SkillLevel. Idea by Heinz van Saanen.
+
   void do_skill_level(Move* best, Move* ponder) {
 
     assert(MultiPV > 1);
@@ -1996,6 +2005,7 @@ split_point_start: // At split points actual search starts from here
     return NULL;
   }
 
+
   // extract_pv_from_tt() builds a PV by adding moves from the transposition table.
   // We consider also failing high nodes and not only VALUE_TYPE_EXACT nodes. This
   // allow to always have a ponder move even when we fail high at root and also a
@@ -2030,6 +2040,7 @@ split_point_start: // At split points actual search starts from here
     do pos.undo_move(pv[--ply]); while (ply);
   }
 
+
   // insert_pv_in_tt() is called at the end of a search iteration, and inserts
   // the PV back into the TT. This makes sure the old PV moves are searched
   // first, even if the old TT entries have been overwritten.
@@ -2173,18 +2184,11 @@ void Thread::idle_loop(SplitPoint* sp) {
 void do_uci_async_cmd(const std::string& cmd) {
 
   if (cmd == "quit")
-  {
-      // Quit the program as soon as possible
-      Limits.ponder = false;
       QuitRequest = StopRequest = true;
-  }
+
   else if (cmd == "stop")
-  {
-      // Stop calculating as soon as possible, but still send the "bestmove"
-      // and possibly the "ponder" token when finishing the search.
-      Limits.ponder = false;
       StopRequest = true;
-  }
+
   else if (cmd == "ponderhit")
   {
       // The opponent has played the expected move. GUI sends "ponderhit" if