X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=76afd5dab4debaea6afaa708b0d751012d7f82a3;hp=3a54bf01b0d4e9ac41632c8f03c40a1f2ce723b7;hb=86ac50403d58ce94efc1f2f3ab85ac25abdb6db9;hpb=002bf4d8dbf804ce8303e01733341a0922af2e71 diff --git a/src/search.cpp b/src/search.cpp index 3a54bf01..76afd5da 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -75,9 +75,6 @@ namespace { int FutilityMoveCounts[2][16]; // [improving][depth] int Reductions[2][2][64][64]; // [pv][improving][depth][moveNumber] - // Threshold used for countermoves based pruning - const int CounterMovePruneThreshold = 0; - template Depth reduction(bool i, Depth d, int mn) { return Reductions[PvNode][i][std::min(d / ONE_PLY, 63)][std::min(mn, 63)] * ONE_PLY; } @@ -90,10 +87,9 @@ namespace { // Skill structure is used to implement strength limit struct Skill { - Skill(int l) : level(l) {} + explicit Skill(int l) : level(l) {} bool enabled() const { return level < 20; } bool time_to_pick(Depth depth) const { return depth / ONE_PLY == 1 + level; } - Move best_move(size_t multiPV) { return best ? best : pick_best(multiPV); } Move pick_best(size_t multiPV); int level; @@ -219,16 +215,7 @@ void Search::clear() { TT.clear(); for (Thread* th : Threads) - { - th->counterMoves.fill(MOVE_NONE); - th->mainHistory.fill(0); - - for (auto& to : th->contHistory) - for (auto& h : to) - h.fill(0); - - th->contHistory[NO_PIECE][0].fill(CounterMovePruneThreshold - 1); - } + th->clear(); Threads.main()->callsCnt = 0; Threads.main()->previousScore = VALUE_INFINITE; @@ -271,11 +258,6 @@ void MainThread::search() { Thread::search(); // Let's start searching! } - // When playing in 'nodes as time' mode, subtract the searched nodes from - // the available ones before exiting. - if (Limits.npmsec) - Time.availableNodes += Limits.inc[us] - Threads.nodes_searched(); - // When we reach the maximum depth, we can arrive here without a raise of // Threads.stop. However, if we are pondering or in an infinite search, // the UCI protocol states that we shouldn't print the best move before the @@ -295,6 +277,11 @@ void MainThread::search() { if (th != this) th->wait_for_search_finished(); + // When playing in 'nodes as time' mode, subtract the searched nodes from + // the available ones before exiting. + if (Limits.npmsec) + Time.availableNodes += Limits.inc[us] - Threads.nodes_searched(); + // Check if there are threads with a better score than main thread Thread* bestThread = this; if ( !this->easyMovePlayed @@ -308,7 +295,9 @@ void MainThread::search() { Depth depthDiff = th->completedDepth - bestThread->completedDepth; Value scoreDiff = th->rootMoves[0].score - bestThread->rootMoves[0].score; - if (scoreDiff > 0 && depthDiff >= 0) + // Select the thread with the best score, always if it is a mate + if ( scoreDiff > 0 + && (depthDiff >= 0 || th->rootMoves[0].score >= VALUE_MATE_IN_MAX_PLY)) bestThread = th; } } @@ -334,7 +323,7 @@ void MainThread::search() { void Thread::search() { - Stack stack[MAX_PLY+7], *ss = stack+4; // To allow referencing (ss-4) and (ss+2) + Stack stack[MAX_PLY+7], *ss = stack+4; // To reference from (ss-4) to (ss+2) Value bestValue, alpha, beta, delta; Move easyMove = MOVE_NONE; MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); @@ -455,16 +444,20 @@ void Thread::search() { // Sort the PV lines searched so far and update the GUI std::stable_sort(rootMoves.begin(), rootMoves.begin() + PVIdx + 1); - if (!mainThread) - continue; - - if (Threads.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000) + if ( mainThread + && (Threads.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)) sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl; } if (!Threads.stop) completedDepth = rootDepth; + // Have we found a "mate in x"? + if ( Limits.mate + && bestValue >= VALUE_MATE_IN_MAX_PLY + && VALUE_MATE - bestValue <= 2 * Limits.mate) + Threads.stop = true; + if (!mainThread) continue; @@ -472,12 +465,6 @@ void Thread::search() { if (skill.enabled() && skill.time_to_pick(rootDepth)) skill.pick_best(multiPV); - // Have we found a "mate in x"? - if ( Limits.mate - && bestValue >= VALUE_MATE_IN_MAX_PLY - && VALUE_MATE - bestValue <= 2 * Limits.mate) - Threads.stop = true; - // Do we have time for the next iteration? Can we stop searching now? if (Limits.use_time_management()) { @@ -526,8 +513,8 @@ void Thread::search() { // If skill level is enabled, swap best PV line with the sub-optimal one if (skill.enabled()) - std::swap(rootMoves[0], *std::find(rootMoves.begin(), - rootMoves.end(), skill.best_move(multiPV))); + std::swap(rootMoves[0], *std::find(rootMoves.begin(), rootMoves.end(), + skill.best ? skill.best : skill.pick_best(multiPV))); } @@ -539,7 +526,7 @@ namespace { Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning) { const bool PvNode = NT == PV; - const bool rootNode = PvNode && (ss-1)->ply == 0; + const bool rootNode = PvNode && ss->ply == 0; assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); @@ -555,7 +542,7 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval; bool ttHit, inCheck, givesCheck, singularExtensionNode, improving; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact; Piece movedPiece; int moveCount, quietCount; @@ -565,15 +552,14 @@ namespace { moveCount = quietCount = ss->moveCount = 0; ss->statScore = 0; bestValue = -VALUE_INFINITE; - ss->ply = (ss-1)->ply + 1; // Check for the available remaining time if (thisThread == Threads.main()) static_cast(thisThread)->check_time(); - // Used to send selDepth info to GUI - if (PvNode && thisThread->selDepth < ss->ply) - thisThread->selDepth = ss->ply; + // Used to send selDepth info to GUI (selDepth counts from 1, ply from 0) + if (PvNode && thisThread->selDepth < ss->ply + 1) + thisThread->selDepth = ss->ply + 1; if (!rootNode) { @@ -596,6 +582,7 @@ namespace { assert(0 <= ss->ply && ss->ply < MAX_PLY); + (ss+1)->ply = ss->ply + 1; ss->currentMove = (ss+1)->excludedMove = bestMove = MOVE_NONE; ss->contHistory = &thisThread->contHistory[NO_PIECE][0]; (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; @@ -661,8 +648,8 @@ namespace { int drawScore = TB::UseRule50 ? 1 : 0; - value = v < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply - : v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply + value = v < -drawScore ? -VALUE_MATE + MAX_PLY + ss->ply + 1 + : v > drawScore ? VALUE_MATE - MAX_PLY - ss->ply - 1 : VALUE_DRAW + 2 * v * drawScore; tte->save(posKey, value_to_tt(value, ss->ply), BOUND_EXACT, @@ -825,6 +812,7 @@ moves_loop: // When in check search starts from here && tte->depth() >= depth - 3 * ONE_PLY; skipQuiets = false; ttCapture = false; + pvExact = PvNode && ttHit && tte->bound() == BOUND_EXACT; // Step 11. Loop through moves // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs @@ -965,6 +953,14 @@ moves_loop: // When in check search starts from here r -= r ? ONE_PLY : DEPTH_ZERO; else { + // Decrease reduction if opponent's move count is high + if ((ss-1)->moveCount > 15) + r -= ONE_PLY; + + // Decrease reduction for exact PV nodes + if (pvExact) + r -= ONE_PLY; + // Increase reduction if ttMove is a capture if (ttCapture) r += ONE_PLY; @@ -987,10 +983,10 @@ moves_loop: // When in check search starts from here - 4000; // Decrease/increase reduction by comparing opponent's stat score - if (ss->statScore > 0 && (ss-1)->statScore < 0) + if (ss->statScore >= 0 && (ss-1)->statScore < 0) r -= ONE_PLY; - else if (ss->statScore < 0 && (ss-1)->statScore > 0) + else if ((ss-1)->statScore >= 0 && ss->statScore < 0) r += ONE_PLY; // Decrease/increase reduction for moves with a good/bad history @@ -1172,7 +1168,7 @@ moves_loop: // When in check search starts from here } ss->currentMove = bestMove = MOVE_NONE; - ss->ply = (ss-1)->ply + 1; + (ss+1)->ply = ss->ply + 1; moveCount = 0; // Check for an instant draw or if the maximum ply has been reached @@ -1187,7 +1183,6 @@ moves_loop: // When in check search starts from here // only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS. ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS : DEPTH_QS_NO_CHECKS; - // Transposition table lookup posKey = pos.key(); tte = TT.probe(posKey, ttHit); @@ -1455,7 +1450,7 @@ moves_loop: // When in check search starts from here int push = ( weakness * int(topScore - rootMoves[i].score) + delta * (rng.rand() % weakness)) / 128; - if (rootMoves[i].score + push > maxScore) + if (rootMoves[i].score + push >= maxScore) { maxScore = rootMoves[i].score + push; best = rootMoves[i].pv[0]; @@ -1593,6 +1588,10 @@ void Tablebases::filter_root_moves(Position& pos, Search::RootMoves& rootMoves) ProbeDepth = Options["SyzygyProbeDepth"] * ONE_PLY; Cardinality = Options["SyzygyProbeLimit"]; + // Don't filter any moves if the user requested analysis on multiple + if (Options["MultiPV"] != 1) + return; + // Skip TB probing when no TB found: !TBLargest -> !TB::Cardinality if (Cardinality > MaxCardinality) {