X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=6208da61b8bb0bec7f30fbaa835a02e518aee8b9;hp=6a16368f288f11e00892f0aea0a34282cc0fe5cd;hb=1c42d153402be9eeed46986a392affee03e1de53;hpb=fe26967ea042b318c26ef6bb600a733d049e2171 diff --git a/src/search.cpp b/src/search.cpp index 6a16368f..6208da61 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -72,8 +72,7 @@ namespace { void extract_pv_from_tt(Position& pos); void insert_pv_in_tt(Position& pos); - std::string pv_info_to_uci(Position& pos, int depth, int selDepth, - Value alpha, Value beta, int pvIdx); + int64_t nodes; Value pv_score; Value non_pv_score; @@ -218,8 +217,10 @@ namespace { void do_skill_level(Move* best, Move* ponder); int current_search_time(int set = 0); - std::string value_to_uci(Value v); + std::string score_to_uci(Value v, Value alpha, Value beta); std::string speed_to_uci(int64_t nodes); + std::string pv_to_uci(Move pv[], int pvNum); + std::string depth_to_uci(Depth depth); void poll(const Position& pos); void wait_for_stop_or_ponderhit(); @@ -404,6 +405,9 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) { Limits = limits; TimeMgr.init(Limits, pos.startpos_ply_counter()); + // Set output steram in normal or chess960 mode + cout << set960(pos.is_chess960()); + // Set best NodesBetweenPolls interval to avoid lagging under time pressure if (Limits.maxNodes) NodesBetweenPolls = Min(Limits.maxNodes, 30000); @@ -480,8 +484,6 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) { Move ponderMove = MOVE_NONE; Move bestMove = id_loop(pos, searchMoves, &ponderMove); - cout << "info" << speed_to_uci(pos.nodes_searched()) << endl; - // Write final search statistics and close log file if (LogFile.is_open()) { @@ -531,7 +533,7 @@ namespace { SearchStack ss[PLY_MAX_PLUS_2]; Value bestValues[PLY_MAX_PLUS_2]; int bestMoveChanges[PLY_MAX_PLUS_2]; - int depth, selDepth, aspirationDelta; + int depth, aspirationDelta; Value value, alpha, beta; Move bestMove, easyMove, skillBest, skillPonder; @@ -548,11 +550,10 @@ namespace { Rml.init(pos, searchMoves); // Handle special case of searching on a mate/stalemate position - if (Rml.size() == 0) + if (!Rml.size()) { - cout << "info depth 0 score " - << value_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW) - << endl; + cout << "info" << depth_to_uci(DEPTH_ZERO) + << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW, alpha, beta) << endl; return MOVE_NONE; } @@ -561,7 +562,6 @@ namespace { while (!StopRequest && ++depth <= PLY_MAX && (!Limits.maxDepth || depth <= Limits.maxDepth)) { Rml.bestMoveChanges = 0; - cout << set960(pos.is_chess960()) << "info depth " << depth << endl; // Calculate dynamic aspiration window based on previous iterations if (MultiPV == 1 && depth >= 5 && abs(bestValues[depth - 1]) < VALUE_KNOWN_WIN) @@ -591,6 +591,16 @@ namespace { if (StopRequest) 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. + if ((value > alpha && value < beta) || current_search_time() > 2000) + for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++) + cout << "info" + << depth_to_uci(depth * ONE_PLY) + << score_to_uci(Rml[i].pv_score, alpha, beta) + << speed_to_uci(pos.nodes_searched()) + << pv_to_uci(Rml[i].pv, i + 1) << endl; + // In case of failing high/low increase aspiration window and research, // otherwise exit the fail high/low loop. if (value >= beta) @@ -621,16 +631,6 @@ namespace { if (SkillLevelEnabled && depth == 1 + SkillLevel) do_skill_level(&skillBest, &skillPonder); - // Retrieve max searched depth among threads - selDepth = 0; - for (int i = 0; i < Threads.size(); i++) - if (Threads[i].maxPly > selDepth) - selDepth = Threads[i].maxPly; - - // Send PV line to GUI and to log file - for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++) - cout << Rml[i].pv_info_to_uci(pos, depth, selDepth, alpha, beta, i) << endl; - if (LogFile.is_open()) LogFile << pretty_pv(pos, depth, value, current_search_time(), Rml[0].pv) << endl; @@ -1004,9 +1004,10 @@ split_point_start: // At split points actual search starts from here cout << "info" << speed_to_uci(pos.nodes_searched()) << endl; } + // For long searches send to GUI current move if (current_search_time() > 2000) - cout << "info currmove " << move - << " currmovenumber " << moveCount << endl; + cout << "info" << depth_to_uci(depth) + << " currmove " << move << " currmovenumber " << moveCount << endl; } // At Root and at first iteration do a PV search on all the moves to score root moves @@ -1226,7 +1227,7 @@ split_point_start: // At split points actual search starts from here Rml.bestMoveChanges++; // It is critical that sorting is done with a stable algorithm - // becuase all the values but the first are usually set to + // because all the values but the first are usually set to // -VALUE_INFINITE and we want to keep the same order for all // the moves but the new PV that goes to head. Rml.sort_first(moveCount); @@ -1764,21 +1765,23 @@ split_point_start: // At split points actual search starts from here } - // value_to_uci() converts a value to a string suitable for use with the UCI + // score_to_uci() converts a value to a string suitable for use with the UCI // protocol specifications: // // cp The score from the engine's point of view in centipawns. // mate Mate in y moves, not plies. If the engine is getting mated // use negative values for y. - std::string value_to_uci(Value v) { + std::string score_to_uci(Value v, Value alpha, Value beta) { std::stringstream s; if (abs(v) < VALUE_MATE - PLY_MAX * ONE_PLY) - s << "cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to centipawns + s << " score cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to centipawns else - s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; + s << " score mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; + + s << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : ""); return s.str(); } @@ -1793,12 +1796,45 @@ split_point_start: // At split points actual search starts from here int t = current_search_time(); s << " nodes " << nodes - << " nps " << (t > 0 ? int(nodes * 1000 / t) : 0) + << " 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. + + std::string pv_to_uci(Move pv[], int pvNum) { + + std::stringstream s; + + s << " multipv " << pvNum << " pv "; + + 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. + + std::string depth_to_uci(Depth depth) { + + std::stringstream s; + + // Retrieve max searched depth among threads + int selDepth = 0; + for (int i = 0; i < Threads.size(); i++) + if (Threads[i].maxPly > selDepth) + selDepth = Threads[i].maxPly; + + s << " depth " << depth / ONE_PLY << " seldepth " << selDepth; + + return s.str(); + } + // poll() performs two different functions: It polls for user input, and it // looks at the time consumed so far and decides if it's time to abort the @@ -2054,27 +2090,6 @@ split_point_start: // At split points actual search starts from here do pos.undo_move(pv[--ply]); while (ply); } - // pv_info_to_uci() returns a string with information on the current PV line - // formatted according to UCI specification. - - std::string RootMove::pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha, - Value beta, int pvIdx) { - std::stringstream s; - - s << "info depth " << depth - << " seldepth " << selDepth - << " multipv " << pvIdx + 1 - << " score " << value_to_uci(pv_score) - << (pv_score >= beta ? " lowerbound" : pv_score <= alpha ? " upperbound" : "") - << speed_to_uci(pos.nodes_searched()) - << " pv "; - - for (Move* m = pv; *m != MOVE_NONE; m++) - s << *m << " "; - - return s.str(); - } - // Specializations for MovePickerExt in case of Root node MovePickerExt::MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, SearchStack* ss, Value b)