X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsearch.cpp;h=e976274f28fd4369dc8793b4782e80ef7e7cabc7;hb=6a6fc28551b84719868df99950584b878199d0c6;hp=b484dcbe062451ade8c78aeadf04855bbaaa9c20;hpb=9ab2590963b029092a378c7a69d1c80c43999db8;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index b484dcbe..e976274f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -61,6 +61,9 @@ namespace { // Different node types, used as a template parameter enum NodeType { NonPV, PV }; + constexpr uint64_t ttHitAverageWindow = 4096; + constexpr uint64_t ttHitAverageResolution = 1024; + // Razor and futility margins constexpr int RazorMargin = 661; Value futility_margin(Depth d, bool improving) { @@ -363,6 +366,7 @@ void Thread::search() { multiPV = std::max(multiPV, (size_t)4); multiPV = std::min(multiPV, rootMoves.size()); + ttHitAverage = ttHitAverageWindow * ttHitAverageResolution / 2; int ct = int(Options["Contempt"]) * PawnValueEg / 100; // From centipawns @@ -665,6 +669,9 @@ namespace { ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ttHit ? tte->move() : MOVE_NONE; ttPv = PvNode || (ttHit && tte->is_pv()); + // thisThread->ttHitAverage can be used to approximate the running average of ttHit + thisThread->ttHitAverage = (ttHitAverageWindow - 1) * thisThread->ttHitAverage / ttHitAverageWindow + + ttHitAverageResolution * ttHit; // At non-PV nodes we check for an early TT cutoff if ( !PvNode @@ -955,7 +962,44 @@ moves_loop: // When in check, search starts from here movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); - // Step 13. Extensions (~70 Elo) + // Calculate new depth for this move + newDepth = depth - 1; + + // Step 13. Pruning at shallow depth (~170 Elo) + if ( !rootNode + && pos.non_pawn_material(us) + && bestValue > VALUE_MATED_IN_MAX_PLY) + { + // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold + moveCountPruning = moveCount >= futility_move_count(improving, depth); + + if ( !captureOrPromotion + && !givesCheck) + { + // Reduced depth of the next LMR search + int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); + + // Countermoves based pruning (~20 Elo) + if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) + && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold + && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) + continue; + + // Futility pruning: parent node (~2 Elo) + if ( lmrDepth < 6 + && !inCheck + && ss->staticEval + 250 + 211 * lmrDepth <= alpha) + continue; + + // Prune moves with negative SEE (~10 Elo) + if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + continue; + } + else if (!pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) + continue; + } + + // Step 14. Extensions (~70 Elo) // Singular extension search (~60 Elo). If all moves but one fail low on a // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), @@ -1005,48 +1049,18 @@ moves_loop: // When in check, search starts from here && pos.pawn_passed(us, to_sq(move))) extension = 1; + // Last captures extension + else if ( PvNode + && PieceValue[EG][pos.captured_piece()] > PawnValueEg + && pos.non_pawn_material() <= 2 * RookValueMg) + extension = 1; + // Castling extension if (type_of(move) == CASTLING) extension = 1; - // Calculate new depth for this move - newDepth = depth - 1 + extension; - - // Step 14. Pruning at shallow depth (~170 Elo) - if ( !rootNode - && pos.non_pawn_material(us) - && bestValue > VALUE_MATED_IN_MAX_PLY) - { - // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold - moveCountPruning = moveCount >= futility_move_count(improving, depth); - - if ( !captureOrPromotion - && !givesCheck - && (!PvNode || !pos.advanced_pawn_push(move) || pos.non_pawn_material(~us) > BishopValueMg)) - { - // Reduced depth of the next LMR search - int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), 0); - - // Countermoves based pruning (~20 Elo) - if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) - && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold - && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) - continue; - - // Futility pruning: parent node (~2 Elo) - if ( lmrDepth < 6 - && !inCheck - && ss->staticEval + 250 + 211 * lmrDepth <= alpha) - continue; - - // Prune moves with negative SEE (~10 Elo) - if (!pos.see_ge(move, Value(-(31 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) - continue; - } - else if ( !(givesCheck && extension) - && !pos.see_ge(move, Value(-199) * depth)) // (~20 Elo) - continue; - } + // Add extension to new depth + newDepth += extension; // Speculative prefetch as early as possible prefetch(TT.first_entry(pos.key_after(move))); @@ -1076,10 +1090,15 @@ moves_loop: // When in check, search starts from here && ( !captureOrPromotion || moveCountPruning || ss->staticEval + PieceValue[EG][pos.captured_piece()] <= alpha - || cutNode)) + || cutNode + || thisThread->ttHitAverage < 384 * ttHitAverageResolution * ttHitAverageWindow / 1024)) { Depth r = reduction(improving, depth, moveCount); + // Decrease reduction if the ttHit running average is large + if (thisThread->ttHitAverage > 544 * ttHitAverageResolution * ttHitAverageWindow / 1024) + r--; + // Reduction if other threads are searching this position. if (th.marked()) r++;