X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=8257b5bb9f33d308ef668539e75ccb4f89567f12;hp=fefc886424e9935116191a27c44594b7ad6d887b;hb=369789b426f1cb63a8855c131855a2e37bc61846;hpb=d58176bfead421088bb3543b3cb6d1c359a3c91b diff --git a/src/search.cpp b/src/search.cpp index fefc8864..8257b5bb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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(); - SkillLevel = Options["Skill Level"].value(); - + // 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(); + SkillLevel = Options["Skill Level"].value(); + // 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()) { Log log(Options["Search Log Filename"].value()); @@ -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()) { 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