diff --git a/src/search.cpp b/src/search.cpp index 2def21d02..d1aaab1ad 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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 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(pos).contains(ttData.move)) + auto [ttHit, ttData, ttWriter] = tt.probe(pos.key()); + if (ttHit && MoveList(pos).contains(ttData.move)) pv.push_back(ttData.move); }