X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=25383aae9d2504801f05e8e82aff4245d3990f61;hp=ad54a7265417d12e4ea7994b4ea3baf34855af43;hb=108f0da4d7f993732aa2e854b8f3fa8ca6d3b46c;hpb=e9aeaad05266ca557a9496b5a17b4c5f82f0e946 diff --git a/src/search.cpp b/src/search.cpp index ad54a726..25383aae 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -48,7 +48,6 @@ namespace Tablebases { bool RootInTB; bool UseRule50; Depth ProbeDepth; - Value Score; } namespace TB = Tablebases; @@ -354,9 +353,20 @@ void Thread::search() { for (RootMove& rm : rootMoves) rm.previousScore = rm.score; + size_t PVFirst = 0; + PVLast = 0; + // MultiPV loop. We perform a full root search for each PV line for (PVIdx = 0; PVIdx < multiPV && !Threads.stop; ++PVIdx) { + if (PVIdx == PVLast) + { + PVFirst = PVLast; + for (PVLast++; PVLast < rootMoves.size(); PVLast++) + if (rootMoves[PVLast].TBRank != rootMoves[PVFirst].TBRank) + break; + } + // Reset UCI info selDepth for each depth and each PV line selDepth = 0; @@ -388,7 +398,7 @@ void Thread::search() { // and we want to keep the same order for all the moves except the // new PV that goes to the front. Note that in case of MultiPV // search the already searched PV lines are preserved. - std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.end()); + std::stable_sort(rootMoves.begin() + PVIdx, rootMoves.begin() + PVLast); // If search has been stopped, we break immediately. Sorting is // safe because RootMoves is still valid, although it refers to @@ -428,7 +438,7 @@ void Thread::search() { } // Sort the PV lines searched so far and update the GUI - std::stable_sort(rootMoves.begin(), rootMoves.begin() + PVIdx + 1); + std::stable_sort(rootMoves.begin() + PVFirst, rootMoves.begin() + PVIdx + 1); if ( mainThread && (Threads.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)) @@ -843,9 +853,10 @@ moves_loop: // When in check, search starts from here // At root obey the "searchmoves" option and skip moves not listed in Root // Move List. As a consequence any illegal move is also skipped. In MultiPV - // mode we also skip PV moves which have been already searched. + // mode we also skip PV moves which have been already searched and those + // of lower "TB rank" if we are in a TB root position. if (rootNode && !std::count(thisThread->rootMoves.begin() + thisThread->PVIdx, - thisThread->rootMoves.end(), move)) + thisThread->rootMoves.begin() + thisThread->PVLast, move)) continue; ss->moveCount = ++moveCount; @@ -1557,7 +1568,7 @@ string UCI::pv(const Position& pos, Depth depth, Value alpha, Value beta) { Value v = updated ? rootMoves[i].score : rootMoves[i].previousScore; bool tb = TB::RootInTB && abs(v) < VALUE_MATE - MAX_PLY; - v = tb ? TB::Score : v; + v = tb ? rootMoves[i].TBScore : v; if (ss.rdbuf()->in_avail()) // Not at first line ss << "\n"; @@ -1618,52 +1629,49 @@ bool RootMove::extract_ponder_from_tt(Position& pos) { return pv.size() > 1; } - -void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves) { +void Tablebases::rank_root_moves(Position& pos, Search::RootMoves& rootMoves) { RootInTB = false; UseRule50 = Options["Syzygy50MoveRule"]; ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY; Cardinality = Options["SyzygyProbeLimit"]; + bool dtz_available = true; - // Skip TB probing when no TB found: !TBLargest -> !TB::Cardinality + // Tables with fewer pieces than SyzygyProbeLimit are searched with + // ProbeDepth == DEPTH_ZERO if (Cardinality > MaxCardinality) { Cardinality = MaxCardinality; ProbeDepth = DEPTH_ZERO; } - if (Cardinality < popcount(pos.pieces()) || pos.can_castle(ANY_CASTLING)) - return; - - // Don't filter any moves if the user requested analysis on multiple - if (Options["MultiPV"] != 1) - return; + if (Cardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING)) + { + // Rank moves using DTZ tables + RootInTB = root_probe(pos, rootMoves); - // If the current root position is in the tablebases, then RootMoves - // contains only moves that preserve the draw or the win. - RootInTB = root_probe(pos, rootMoves, TB::Score); + if (!RootInTB) + { + // DTZ tables are missing; try to rank moves using WDL tables + dtz_available = false; + RootInTB = root_probe_wdl(pos, rootMoves); + } + } if (RootInTB) - Cardinality = 0; // Do not probe tablebases during the search - - else // If DTZ tables are missing, use WDL tables as a fallback { - // Filter out moves that do not preserve the draw or the win. - RootInTB = root_probe_wdl(pos, rootMoves, TB::Score); + // Sort moves according to TB rank + std::sort(rootMoves.begin(), rootMoves.end(), + [](const RootMove &a, const RootMove &b) { return a.TBRank > b.TBRank; } ); - // Only probe during search if winning - if (RootInTB && TB::Score <= VALUE_DRAW) + // Probe during search only if DTZ is not available and we are winning + if (dtz_available || rootMoves[0].TBScore <= VALUE_DRAW) Cardinality = 0; } - - if (RootInTB && !UseRule50) - TB::Score = TB::Score > VALUE_DRAW ? VALUE_MATE - MAX_PLY - 1 - : TB::Score < VALUE_DRAW ? -VALUE_MATE + MAX_PLY + 1 - : VALUE_DRAW; - - // Since root_probe() and root_probe_wdl() dirty the root move scores, - // we reset them to -VALUE_INFINITE - for (RootMove& rm : rootMoves) - rm.score = -VALUE_INFINITE; + else + { + // Assign the same rank to all moves + for (auto& m : rootMoves) + m.TBRank = 0; + } }