mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 00:33:09 +00:00
Rewrite how uci info is sent to GUI
It is now much more modular than before and also we always send the seldepth when we send the depth, this avoids to make seldepth disappearing from GUI at the start of a new iteration. Print also fails high/low pv lines at high enough search depths. No functional change. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
fe26967ea0
commit
1c42d15340
1 changed files with 65 additions and 50 deletions
115
src/search.cpp
115
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 <x> The score from the engine's point of view in centipawns.
|
||||
// mate <y> 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<Root>::MovePickerExt(const Position& p, Move ttm, Depth d,
|
||||
const History& h, SearchStack* ss, Value b)
|
||||
|
|
Loading…
Add table
Reference in a new issue