1
0
Fork 0
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:
Marco Costalba 2011-06-22 07:03:28 +01:00
parent fe26967ea0
commit 1c42d15340

View file

@ -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)