X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsearch.cpp;h=5d54a15d628070707d6f08db5b7e6483635b3d27;hb=b36d39de3d61b8f31c11d85233631aafaf760ee1;hp=b2983f6647ae860093d9d92d9587cd7faa23437e;hpb=b973e40e45d75c3b3391141d149d4186494d4652;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index b2983f66..5d54a15d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -72,7 +72,7 @@ namespace { Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) { int r = Reductions[d] * Reductions[mn]; - return (r + 1449 - int(delta) * 1032 / int(rootDelta)) / 1024 + (!i && r > 941); + return (r + 1449 - int(delta) * 937 / int(rootDelta)) / 1024 + (!i && r > 941); } constexpr int futility_move_count(bool improving, Depth depth) { @@ -82,7 +82,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return std::min(340 * d - 470, 1855); + return std::min(341 * d - 470, 1710); } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -290,9 +290,18 @@ void Thread::search() { bestValue = delta = alpha = -VALUE_INFINITE; beta = VALUE_INFINITE; + optimism[WHITE] = optimism[BLACK] = VALUE_ZERO; if (mainThread) { + + if (!rootPos.checkers()) + { + int rootComplexity; + Eval::evaluate(rootPos, &rootComplexity); + mainThread->complexity = std::min(1.03 + (rootComplexity - 241) / 1552.0, 1.45); + } + if (mainThread->bestPreviousScore == VALUE_INFINITE) for (int i = 0; i < 4; ++i) mainThread->iterValue[i] = VALUE_ZERO; @@ -311,10 +320,6 @@ void Thread::search() { multiPV = std::min(multiPV, rootMoves.size()); - complexityAverage.set(153, 1); - - optimism[us] = optimism[~us] = VALUE_ZERO; - int searchAgainCounter = 0; // Iterative deepening loop until requested to stop or the target depth is reached @@ -472,10 +477,8 @@ void Thread::search() { timeReduction = lastBestMoveDepth + 8 < completedDepth ? 1.57 : 0.65; double reduction = (1.4 + mainThread->previousTimeReduction) / (2.08 * timeReduction); double bestMoveInstability = 1 + 1.8 * totBestMoveChanges / Threads.size(); - int complexity = mainThread->complexityAverage.value(); - double complexPosition = std::min(1.03 + (complexity - 241) / 1552.0, 1.45); - double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition; + double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * mainThread->complexity; // Cap used time in case of a single legal move for a better viewer experience in tournaments // yielding correct scores and sufficiently fast moves. @@ -607,14 +610,7 @@ namespace { (ss+2)->cutoffCnt = 0; ss->doubleExtensions = (ss-1)->doubleExtensions; Square prevSq = is_ok((ss-1)->currentMove) ? to_sq((ss-1)->currentMove) : SQ_NONE; - - // Initialize statScore to zero for the grandchildren of the current position. - // So statScore is shared between all grandchildren and only the first grandchild - // starts with statScore = 0. Later grandchildren start with the last calculated - // statScore of the previous grandchild. This influences the reduction rules in - // LMR which are based on the statScore of parent position. - if (!rootNode) - (ss+2)->statScore = 0; + ss->statScore = 0; // Step 4. Transposition table lookup. excludedMove = ss->excludedMove; @@ -762,8 +758,6 @@ namespace { tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } - thisThread->complexityAverage.update(complexity); - // Use static evaluation difference to improve quiet move ordering (~4 Elo) if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) { @@ -783,7 +777,7 @@ namespace { // Step 7. Razoring (~1 Elo). // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. - if (eval < alpha - 426 - 252 * depth * depth) + if (eval < alpha - 426 - 256 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -805,7 +799,7 @@ namespace { && (ss-1)->statScore < 18755 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 19 * depth - improvement / 13 + 253 + complexity / 25 + && ss->staticEval >= beta - 20 * depth - improvement / 13 + 253 + complexity / 25 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -813,7 +807,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth, eval and complexity of position - Depth R = std::min(int(eval - beta) / 168, 6) + depth / 3 + 4 - (complexity > 825); + Depth R = std::min(int(eval - beta) / 172, 6) + depth / 3 + 4 - (complexity > 825); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -903,11 +897,11 @@ namespace { Eval::NNUE::hint_common_parent_position(pos); } - // Step 11. If the position is not in TT, decrease depth by 3. + // Step 11. If the position is not in TT, decrease depth by 2 (or by 4 if the TT entry for the current position was hit and the stored depth is greater than or equal to the current depth). // Use qsearch if depth is equal or below zero (~9 Elo) if ( PvNode && !ttMove) - depth -= 3; + depth -= 2 + 2 * (ss->ttHit && tte->depth() >= depth); if (depth <= 0) return qsearch(pos, ss, alpha, beta); @@ -1012,7 +1006,6 @@ moves_loop: // When in check, search starts here { // Futility pruning for captures (~2 Elo) if ( !givesCheck - && !PvNode && lmrDepth < 6 && !ss->inCheck && ss->staticEval + 182 + 230 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] @@ -1065,9 +1058,8 @@ moves_loop: // When in check, search starts here lmrDepth = std::max(lmrDepth, 0); - Bitboard occupied; // Prune moves with negative SEE (~4 Elo) - if (!pos.see_ge(move, occupied, Value(-24 * lmrDepth * lmrDepth - 15 * lmrDepth))) + if (!pos.see_ge(move, Value(-24 * lmrDepth * lmrDepth - 16 * lmrDepth))) continue; } } @@ -1190,11 +1182,6 @@ moves_loop: // When in check, search starts here if (singularQuietLMR) r--; - // Decrease reduction if we move a threatened piece (~1 Elo) - if ( depth > 9 - && (mp.threatenedPieces & from_sq(move))) - r--; - // Increase reduction if next ply has a lot of fail high (~5 Elo) if ((ss+1)->cutoffCnt > 3) r++; @@ -1208,10 +1195,10 @@ moves_loop: // When in check, search starts here + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - - 4182; + - 4082; // Decrease/increase reduction for moves with a good/bad history (~25 Elo) - r -= ss->statScore / (11791 + 3992 * (depth > 6 && depth < 19)); + r -= ss->statScore / (11079 + 4626 * (depth > 6 && depth < 19)); // Step 17. Late moves reduction / extension (LMR, ~117 Elo) // We use various heuristics for the sons of a node after the first son has @@ -1272,6 +1259,9 @@ moves_loop: // When in check, search starts here (ss+1)->pv[0] = MOVE_NONE; value = -search(pos, ss+1, -beta, -alpha, newDepth, false); + + if (moveCount > 1 && newDepth >= depth && !capture) + update_continuation_histories(ss, movedPiece, to_sq(move), -stat_bonus(newDepth)); } // Step 19. Undo move @@ -1345,16 +1335,18 @@ moves_loop: // When in check, search starts here if (PvNode && value < beta) // Update alpha! Always alpha < beta { - alpha = value; // Reduce other moves if we have found at least one score improvement (~1 Elo) if ( depth > 1 - && depth < 6 - && beta < 10534 - && alpha > -10534) - depth -= 1; + && ((improving && complexity > 971) || (value < (5 * alpha + 75 * beta) / 87) || depth < 6) + && beta < 12535 + && value > -12535) { + bool extraReduction = depth > 2 && alpha > -12535 && bestValue != -VALUE_INFINITE && (value - bestValue) > (7 * (beta - alpha)) / 8; + depth -= 1 + extraReduction; + } assert(depth > 0); + alpha = value; } else { @@ -1552,7 +1544,6 @@ moves_loop: // When in check, search starts here prevSq); int quietCheckEvasions = 0; - Bitboard occupied; // Step 5. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. @@ -1589,7 +1580,7 @@ moves_loop: // When in check, search starts here continue; } - if (futilityBase <= alpha && !pos.see_ge(move, occupied, VALUE_ZERO + 1)) + if (futilityBase <= alpha && !pos.see_ge(move, VALUE_ZERO + 1)) { bestValue = std::max(bestValue, futilityBase); continue; @@ -1608,7 +1599,7 @@ moves_loop: // When in check, search starts here continue; // Do not search moves with bad enough SEE values (~5 Elo) - if (!pos.see_ge(move, occupied, Value(-110))) + if (!pos.see_ge(move, Value(-110))) continue; }