@@ -152,11 +152,12 @@ std::string Match::convertScoreToString(engine::Score score) {
152152 return " ERR" ;
153153}
154154
155- void Match::addMoveData (const Player& player, const std::string& move, int64_t measured_time_ms, int64_t latency,
155+ void Match::addMoveData (const Player& player, const std::string& move, const std::string& ponder, int64_t measured_time_ms, int64_t latency,
156156 int64_t timeleft, bool legal) {
157157 MoveData move_data;
158158
159159 move_data.move = move;
160+ move_data.ponder = ponder;
160161 move_data.score_string = " 0.00" ;
161162 move_data.elapsed_millis = measured_time_ms;
162163 move_data.legal = legal;
@@ -211,7 +212,8 @@ void Match::addMoveData(const Player& player, const std::string& move, int64_t m
211212 }
212213 }
213214
214- verifyPvLines (player, legal ? move : " " );
215+ // only warn on PV/bestmove mismatch if the move is legal
216+ verifyPvLines (player, legal ? move : " " , ponder);
215217
216218 data_.moves .push_back (move_data);
217219}
@@ -400,15 +402,17 @@ bool Match::playMove(Player& us, Player& them) {
400402 LOG_INFO_THREAD (" Engine {} latency: {}ms (elapsed: {}, reported: {})" , name, latency, elapsed_ms, last_time);
401403 }
402404
403- const auto best_move = us.engine .bestmove (status.code == engine::process::Status::OK );
405+ const auto bestmove = us.engine .bestmove (status.code == engine::process::Status::OK );
406+ const auto best_move = bestmove.first ;
404407 const auto move = best_move && uci::isUciMove (*best_move) ? uci::uciToMove (board_, *best_move) : Move::NO_MOVE ;
405408 const auto legal = isLegal (move);
406409
407410 const auto timeout = us.hasTimeControl () ? !us.getTimeControl ().updateTime (elapsed_ms) : false ;
408411 const auto timeleft = us.hasTimeControl () ? us.getTimeControl ().getTimeLeft () : 0 ;
409412
410413 if (best_move) {
411- addMoveData (us, *best_move, elapsed_ms, latency, timeleft, legal);
414+ const auto ponder = bestmove.second ;
415+ addMoveData (us, *best_move, ponder ? *ponder : " " , elapsed_ms, latency, timeleft, legal);
412416 }
413417
414418 // there are two reasons why best_move could be empty
@@ -577,7 +581,7 @@ void Match::setEngineIllegalMoveStatus(Player& loser, Player& winner, const std:
577581 Logger::print<Logger::Level::WARN >(" Warning; Illegal move {} played by {}" , best_move.value_or (" <none>" ), name);
578582}
579583
580- void Match::verifyPvLines (const Player& us, const std::string& best_move) {
584+ void Match::verifyPvLines (const Player& us, const std::string& best_move, const std::string& ponder_move ) {
581585 const static auto verifyPv = [](Board board, const std::string& startpos,
582586 const std::vector<std::string_view>& uci_moves, const std::string& info,
583587 std::string_view name) {
@@ -685,7 +689,7 @@ void Match::verifyPvLines(const Player& us, const std::string& best_move) {
685689 verifyPv (board_, start_position_, data_.getMoves (), *info, us.engine .getConfig ().name );
686690 }
687691
688- // finally check if the final PV matches bestmove
692+ // finally check if the final PV matches bestmove (and possibly ponder move)
689693 if (best_move.empty ()) {
690694 return ;
691695 }
@@ -706,17 +710,36 @@ void Match::verifyPvLines(const Player& us, const std::string& best_move) {
706710 return ;
707711 }
708712
709- if (best_move != (*pv)[0 ]) {
710- auto warning = " Warning; Bestmove does not match beginning of last PV - move {} from {}" ;
713+ for (unsigned int i = 0 ; i < 2 ; i++) {
714+ if (i && (ponder_move.empty () || (!config::TournamentConfig->warn_ponder_pv_short && pv->size () < 2 ))) {
715+ break ;
716+ }
717+
718+ const auto &value = i ? ponder_move : best_move;
719+ if (i < pv->size () && value == (*pv)[i]) {
720+ continue ;
721+ }
722+
723+ std::string warning;
724+ if (i && pv->size () == 1 ) {
725+ warning = " Warning; PV has length 1 despite ponder move output - move {} from {}" ;
726+ } else {
727+ warning =
728+ " Warning; " s + (i ? " Ponder" : " Best" ) + " move does not match beginning of last PV - move {} from {}" ;
729+ }
730+
711731 auto start_pos = start_position_ == " startpos" ? " startpos" : (" fen " + start_position_);
712- auto out = fmt::format (fmt::runtime (warning), best_move , us.engine .getConfig ().name );
732+ auto out = fmt::format (fmt::runtime (warning), value , us.engine .getConfig ().name );
713733 auto uci_info = fmt::format (" Info; {}" , info);
714734 auto position = fmt::format (" Position; {}" , start_pos);
715735 auto ucimoves = fmt::format (" Moves; {}" , str_utils::join (data_.getMoves (), " " ));
716736
717737 auto separator = config::TournamentConfig->test_env ? " :: " : " \n " ;
718738
719739 Logger::print<Logger::Level::WARN >(" {1}{0}{2}{0}{3}{0}{4}" , separator, out, uci_info, position, ucimoves);
740+
741+ // Do not emit ponder move warning if already the bestmove does not match PV
742+ break ;
720743 }
721744}
722745
0 commit comments