mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 20:57:10 +00:00
Align ponder move and final PV output
In master for various reasons the given ponder move may get out of sync with (the second move of) the last PV sent to the GUI: 1. If a ponder move is extracted from the TT despite bestmove leading to a game ending draw. 2. If a ponder move is extracted from the TT from a fail high/low, since after the ponder move extraction no new PV is sent to the GUI. 3. If `syzygy_extend_pv()` from within the call to `pv()` changes the PV after the ponder move has been selected. 4. If the PV roll-back to protect mated-in scores differs in the second move from the final PV sent to the GUI. This PR keeps ponder move and the last printed PV in sync. Fixes #6676. closes https://github.com/official-stockfish/Stockfish/pull/6679 No functional change
This commit is contained in:
committed by
Disservin
parent
d173a0655d
commit
b9f3273af1
+25
-28
@@ -239,14 +239,18 @@ void Search::Worker::start_searching() {
|
||||
main_manager()->bestPreviousScore = bestThread->rootMoves[0].score;
|
||||
main_manager()->bestPreviousAverageScore = bestThread->rootMoves[0].averageScore;
|
||||
|
||||
// Send again PV info if we have a new best thread
|
||||
if (bestThread != this)
|
||||
std::string ponder;
|
||||
bool extractedPonder = false;
|
||||
|
||||
if (bestThread->rootMoves[0].pv.size() == 1)
|
||||
extractedPonder = bestThread->rootMoves[0].extract_ponder_from_tt(tt, rootPos);
|
||||
|
||||
// Send again PV info if we have a new best thread or extracted a ponder move.
|
||||
if (bestThread != this || extractedPonder)
|
||||
main_manager()->pv(*bestThread, threads, tt, bestThread->completedDepth);
|
||||
|
||||
std::string ponder;
|
||||
|
||||
if (bestThread->rootMoves[0].pv.size() > 1
|
||||
|| bestThread->rootMoves[0].extract_ponder_from_tt(tt, rootPos))
|
||||
// In rare cases, pv() may change the ponder move through syzygy_extend_pv().
|
||||
if (bestThread->rootMoves[0].pv.size() > 1)
|
||||
ponder = UCIEngine::move(bestThread->rootMoves[0].pv[1], rootPos.is_chess960());
|
||||
|
||||
auto bestmove = UCIEngine::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960());
|
||||
@@ -262,9 +266,7 @@ void Search::Worker::iterative_deepening() {
|
||||
|
||||
Move pv[MAX_PLY + 1];
|
||||
|
||||
Depth lastBestMoveDepth = 0;
|
||||
Value lastBestScore = -VALUE_INFINITE;
|
||||
std::vector<Move> lastBestPV;
|
||||
Depth lastBestMoveDepth = 0;
|
||||
|
||||
Value alpha, beta;
|
||||
Value bestValue = -VALUE_INFINITE;
|
||||
@@ -428,8 +430,7 @@ void Search::Worker::iterative_deepening() {
|
||||
// PV that cannot be trusted, i.e. it can be delayed or refuted if we
|
||||
// would have had time to fully search other root-moves. Thus here we
|
||||
// suppress any exact mated-in/TB loss output and, if we do, below pick
|
||||
// the score/PV from the previously completed iteration with the most
|
||||
// recent bestmove change.
|
||||
// the score/PV from the previous iteration.
|
||||
&& !(threads.stop && is_loss(rootMoves[0].uciScore)
|
||||
&& rootMoves[0].score == rootMoves[0].uciScore))
|
||||
main_manager()->pv(*this, threads, tt, rootDepth);
|
||||
@@ -440,7 +441,11 @@ void Search::Worker::iterative_deepening() {
|
||||
|
||||
if (!threads.stop)
|
||||
{
|
||||
completedDepth = rootDepth;
|
||||
completedDepth = rootDepth;
|
||||
|
||||
if (lastIterationPV.empty() || rootMoves[0].pv[0] != lastIterationPV[0])
|
||||
lastBestMoveDepth = rootDepth;
|
||||
|
||||
lastIterationPV = rootMoves[0].pv;
|
||||
}
|
||||
|
||||
@@ -451,14 +456,12 @@ void Search::Worker::iterative_deepening() {
|
||||
{
|
||||
// Bring the last best move to the front for best thread selection.
|
||||
// For an aborted d1 search we label the loss score as inexact.
|
||||
if (!lastBestPV.empty())
|
||||
if (!lastIterationPV.empty())
|
||||
{
|
||||
Utility::move_to_front(rootMoves,
|
||||
[&lastBestPV = std::as_const(lastBestPV)](const auto& rm) {
|
||||
return rm == lastBestPV[0];
|
||||
});
|
||||
rootMoves[0].pv = lastBestPV;
|
||||
rootMoves[0].score = rootMoves[0].uciScore = lastBestScore;
|
||||
Utility::move_to_front(rootMoves, [&lastPV = std::as_const(lastIterationPV)](
|
||||
const auto& rm) { return rm == lastPV[0]; });
|
||||
rootMoves[0].pv = lastIterationPV;
|
||||
rootMoves[0].score = rootMoves[0].uciScore = rootMoves[0].previousScore;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -468,12 +471,6 @@ void Search::Worker::iterative_deepening() {
|
||||
main_manager()->pv(*this, threads, tt, rootDepth);
|
||||
}
|
||||
}
|
||||
else if (lastBestPV.empty() || rootMoves[0].pv[0] != lastBestPV[0])
|
||||
{
|
||||
lastBestPV = rootMoves[0].pv;
|
||||
lastBestScore = rootMoves[0].score;
|
||||
lastBestMoveDepth = rootDepth;
|
||||
}
|
||||
|
||||
// Have we found a "mate in x" after a completed iteration?
|
||||
if (limits.mate && !threads.stop
|
||||
@@ -2223,10 +2220,10 @@ bool RootMove::extract_ponder_from_tt(const TranspositionTable& tt, Position& po
|
||||
|
||||
pos.do_move(pv[0], st, &tt);
|
||||
|
||||
auto [ttHit, ttData, ttWriter] = tt.probe(pos.key());
|
||||
if (ttHit)
|
||||
if (!pos.is_draw(1))
|
||||
{
|
||||
if (MoveList<LEGAL>(pos).contains(ttData.move))
|
||||
auto [ttHit, ttData, ttWriter] = tt.probe(pos.key());
|
||||
if (ttHit && MoveList<LEGAL>(pos).contains(ttData.move))
|
||||
pv.push_back(ttData.move);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user