1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-29 16:23:09 +00:00

Refactor pv printing

Also fix the case which is currently printing depth 0.

fixes #5019
closes https://github.com/official-stockfish/Stockfish/pull/5020

No functional change
This commit is contained in:
Disservin 2024-01-27 22:27:22 +01:00 committed by Joost VandeVondele
parent 13eb023fc0
commit 16afec0582
4 changed files with 66 additions and 79 deletions

View file

@ -27,6 +27,7 @@
#include <initializer_list>
#include <iostream>
#include <utility>
#include <sstream>
#include "evaluate.h"
#include "misc.h"
@ -192,9 +193,7 @@ void Search::Worker::start_searching() {
// Send again PV info if we have a new best thread
if (bestThread != this)
sync_cout << UCI::pv(*bestThread, main_manager()->tm.elapsed(threads.nodes_searched()),
threads.nodes_searched(), threads.tb_hits(), tt.hashfull(),
tbConfig.rootInTB)
sync_cout << main_manager()->pv(*bestThread, threads, tt, bestThread->completedDepth)
<< sync_endl;
sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960());
@ -336,10 +335,7 @@ void Search::Worker::iterative_deepening() {
// the UI) before a re-search.
if (mainThread && multiPV == 1 && (bestValue <= alpha || bestValue >= beta)
&& mainThread->tm.elapsed(threads.nodes_searched()) > 3000)
sync_cout << UCI::pv(*this, mainThread->tm.elapsed(threads.nodes_searched()),
threads.nodes_searched(), threads.tb_hits(), tt.hashfull(),
tbConfig.rootInTB)
<< sync_endl;
sync_cout << main_manager()->pv(*this, threads, tt, rootDepth) << sync_endl;
// In case of failing low/high increase aspiration window and
// re-search, otherwise exit the loop.
@ -376,10 +372,7 @@ void Search::Worker::iterative_deepening() {
// had time to fully search other root-moves. Thus we suppress this output and
// below pick a proven score/PV for this thread (from the previous iteration).
&& !(threads.abortedSearch && rootMoves[0].uciScore <= VALUE_TB_LOSS_IN_MAX_PLY))
sync_cout << UCI::pv(*this, mainThread->tm.elapsed(threads.nodes_searched()),
threads.nodes_searched(), threads.tb_hits(), tt.hashfull(),
tbConfig.rootInTB)
<< sync_endl;
sync_cout << main_manager()->pv(*this, threads, tt, rootDepth) << sync_endl;
}
if (!threads.stop)
@ -1878,6 +1871,61 @@ void SearchManager::check_time(Search::Worker& worker) {
worker.threads.stop = worker.threads.abortedSearch = true;
}
std::string SearchManager::pv(const Search::Worker& worker,
const ThreadPool& threads,
const TranspositionTable& tt,
Depth depth) const {
std::stringstream ss;
const auto nodes = threads.nodes_searched();
const auto& rootMoves = worker.rootMoves;
const auto& pos = worker.rootPos;
size_t pvIdx = worker.pvIdx;
TimePoint time = tm.elapsed(nodes) + 1;
size_t multiPV = std::min(size_t(worker.options["MultiPV"]), rootMoves.size());
uint64_t tbHits = threads.tb_hits() + (worker.tbConfig.rootInTB ? rootMoves.size() : 0);
for (size_t i = 0; i < multiPV; ++i)
{
bool updated = rootMoves[i].score != -VALUE_INFINITE;
if (depth == 1 && !updated && i > 0)
continue;
Depth d = updated ? depth : std::max(1, depth - 1);
Value v = updated ? rootMoves[i].uciScore : rootMoves[i].previousScore;
if (v == -VALUE_INFINITE)
v = VALUE_ZERO;
bool tb = worker.tbConfig.rootInTB && std::abs(v) <= VALUE_TB;
v = tb ? rootMoves[i].tbScore : v;
if (ss.rdbuf()->in_avail()) // Not at first line
ss << "\n";
ss << "info"
<< " depth " << d << " seldepth " << rootMoves[i].selDepth << " multipv " << i + 1
<< " score " << UCI::value(v);
if (worker.options["UCI_ShowWDL"])
ss << UCI::wdl(v, pos.game_ply());
if (i == pvIdx && !tb && updated) // tablebase- and previous-scores are exact
ss << (rootMoves[i].scoreLowerbound
? " lowerbound"
: (rootMoves[i].scoreUpperbound ? " upperbound" : ""));
ss << " nodes " << nodes << " nps " << nodes * 1000 / time << " hashfull " << tt.hashfull()
<< " tbhits " << tbHits << " time " << time << " pv";
for (Move m : rootMoves[i].pv)
ss << " " << UCI::move(m, pos.is_chess960());
}
return ss.str();
}
// Called in case we have no ponder move before exiting the search,
// for instance, in case we stop the search during a fail high at root.
// We try hard to have a ponder move to return to the GUI,

View file

@ -26,6 +26,7 @@
#include <cstdint>
#include <memory>
#include <vector>
#include <string>
#include "misc.h"
#include "movepick.h"
@ -150,6 +151,11 @@ class SearchManager: public ISearchManager {
public:
void check_time(Search::Worker& worker) override;
std::string pv(const Search::Worker& worker,
const ThreadPool& threads,
const TranspositionTable& tt,
Depth depth) const;
Stockfish::TimeManagement tm;
int callsCnt;
std::atomic_bool ponder;

View file

@ -28,6 +28,7 @@
#include <optional>
#include <sstream>
#include <vector>
#include <cstdint>
#include "benchmark.h"
#include "evaluate.h"
@ -365,63 +366,6 @@ std::string UCI::move(Move m, bool chess960) {
return move;
}
std::string UCI::pv(const Search::Worker& workerThread,
TimePoint elapsed,
uint64_t nodesSearched,
uint64_t tb_hits,
int hashfull,
bool rootInTB) {
std::stringstream ss;
TimePoint time = elapsed + 1;
const auto& rootMoves = workerThread.rootMoves;
const auto& depth = workerThread.completedDepth;
const auto& pos = workerThread.rootPos;
size_t pvIdx = workerThread.pvIdx;
size_t multiPV = std::min(size_t(workerThread.options["MultiPV"]), rootMoves.size());
uint64_t tbHits = tb_hits + (rootInTB ? rootMoves.size() : 0);
for (size_t i = 0; i < multiPV; ++i)
{
bool updated = rootMoves[i].score != -VALUE_INFINITE;
if (depth == 1 && !updated && i > 0)
continue;
Depth d = updated ? depth : std::max(1, depth - 1);
Value v = updated ? rootMoves[i].uciScore : rootMoves[i].previousScore;
if (v == -VALUE_INFINITE)
v = VALUE_ZERO;
bool tb = rootInTB && std::abs(v) <= VALUE_TB;
v = tb ? rootMoves[i].tbScore : v;
if (ss.rdbuf()->in_avail()) // Not at first line
ss << "\n";
ss << "info"
<< " depth " << d << " seldepth " << rootMoves[i].selDepth << " multipv " << i + 1
<< " score " << value(v);
if (workerThread.options["UCI_ShowWDL"])
ss << wdl(v, pos.game_ply());
if (i == pvIdx && !tb && updated) // tablebase- and previous-scores are exact
ss << (rootMoves[i].scoreLowerbound
? " lowerbound"
: (rootMoves[i].scoreUpperbound ? " upperbound" : ""));
ss << " nodes " << nodesSearched << " nps " << nodesSearched * 1000 / time << " hashfull "
<< hashfull << " tbhits " << tbHits << " time " << time << " pv";
for (Move m : rootMoves[i].pv)
ss << " " << move(m, pos.is_chess960());
}
return ss.str();
}
namespace {
// The win rate model returns the probability of winning (in per mille units) given an
// eval and a game ply. It fits the LTC fishtest statistics rather accurately.

View file

@ -19,7 +19,6 @@
#ifndef UCI_H_INCLUDED
#define UCI_H_INCLUDED
#include <cstdint>
#include <iostream>
#include <string>
#include <unordered_map>
@ -37,10 +36,6 @@ namespace Eval::NNUE {
enum NetSize : int;
}
namespace Search {
class Worker;
}
class Move;
enum Square : int;
using Value = int;
@ -55,12 +50,6 @@ class UCI {
static std::string value(Value v);
static std::string square(Square s);
static std::string move(Move m, bool chess960);
static std::string pv(const Search::Worker& workerThread,
TimePoint elapsed,
uint64_t nodesSearched,
uint64_t tb_hits,
int hashfull,
bool rootInTB);
static std::string wdl(Value v, int ply);
static Move to_move(const Position& pos, std::string& str);