X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=9f005587aa4c5845a0a1fcf0b9031be23f59bbc2;hp=3eb8e9e1ee867e0595b6b2a247fe13db633575c5;hb=4231d99ab408674115623f42f7ff89f3f189ca23;hpb=135caee606c86ade9e9c199ef469661c374eb9ba diff --git a/src/search.cpp b/src/search.cpp index 3eb8e9e1..9f005587 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -80,7 +80,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return d > 14 ? 73 : 6 * d * d + 229 * d - 215; + return std::min((6 * d + 229) * d - 215 , 2000); } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -332,7 +332,6 @@ void Thread::search() { multiPV = std::min(multiPV, rootMoves.size()); - ttHitAverage.set(50, 100); // initialize the running average at 50% doubleExtensionAverage[WHITE].set(0, 100); // initialize the running average at 0% doubleExtensionAverage[BLACK].set(0, 100); // initialize the running average at 0% @@ -591,13 +590,13 @@ namespace { bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularQuietLMR, noLMRExtension; Piece movedPiece; - int moveCount, captureCount, quietCount; + int moveCount, captureCount, quietCount, bestMoveCount, improvement; // Step 1. Initialize node ss->inCheck = pos.checkers(); priorCapture = pos.captured_piece(); Color us = pos.side_to_move(); - moveCount = captureCount = quietCount = ss->moveCount = 0; + moveCount = bestMoveCount = captureCount = quietCount = ss->moveCount = 0; bestValue = -VALUE_INFINITE; maxValue = VALUE_INFINITE; @@ -659,6 +658,7 @@ namespace { ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ss->ttHit ? tte->move() : MOVE_NONE; + ttCapture = ttMove && pos.capture_or_promotion(ttMove); if (!excludedMove) ss->ttPv = PvNode || (ss->ttHit && tte->is_pv()); @@ -670,9 +670,6 @@ namespace { && is_ok((ss-1)->currentMove)) thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); - // running average of ttHit - thisThread->ttHitAverage.update(ss->ttHit); - // At non-PV nodes we check for an early TT cutoff if ( !PvNode && ss->ttHit @@ -687,7 +684,7 @@ namespace { if (ttValue >= beta) { // Bonus for a quiet ttMove that fails high - if (!pos.capture_or_promotion(ttMove)) + if (!ttCapture) update_quiet_stats(pos, ss, ttMove, stat_bonus(depth), depth); // Extra penalty for early quiet moves of the previous ply @@ -695,7 +692,7 @@ namespace { update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); } // Penalty for a quiet ttMove that fails low - else if (!pos.capture_or_promotion(ttMove)) + else if (!ttCapture) { int penalty = -stat_bonus(depth); thisThread->mainHistory[us][from_to(ttMove)] << penalty; @@ -769,6 +766,7 @@ namespace { // Skip early pruning when in check ss->staticEval = eval = VALUE_NONE; improving = false; + improvement = 0; goto moves_loop; } else if (ss->ttHit) @@ -790,7 +788,6 @@ namespace { else { // In case of null move search use previous static eval with a different sign - // and addition of two tempos if ((ss-1)->currentMove != MOVE_NULL) ss->staticEval = eval = evaluate(pos); else @@ -808,13 +805,15 @@ namespace { thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus; } - // Set up improving flag that is used in various pruning heuristics - // We define position as improving if static evaluation of position is better - // Than the previous static evaluation at our turn - // In case of us being in check at our previous move we look at move prior to it - improving = (ss-2)->staticEval == VALUE_NONE - ? ss->staticEval > (ss-4)->staticEval || (ss-4)->staticEval == VALUE_NONE - : ss->staticEval > (ss-2)->staticEval; + // Set up the improvement variable, which is the difference between the current + // static evaluation and the previous static evaluation at our turn (if we were + // in check at our previous move we look at the move prior to it). The improvement + // margin and the improving flag are used in various pruning heuristics. + improvement = (ss-2)->staticEval != VALUE_NONE ? ss->staticEval - (ss-2)->staticEval + : (ss-4)->staticEval != VALUE_NONE ? ss->staticEval - (ss-4)->staticEval + : 200; + + improving = improvement > 0; // Step 7. Futility pruning: child node (~50 Elo). // The depth condition is important for mate finding. @@ -830,7 +829,7 @@ namespace { && (ss-1)->statScore < 23767 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 20 * depth - 22 * improving + 168 * ss->ttPv + 177 + && ss->staticEval >= beta - 20 * depth - improvement / 15 + 168 * ss->ttPv + 177 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -953,7 +952,6 @@ namespace { moves_loop: // When in check, search starts here - ttCapture = ttMove && pos.capture_or_promotion(ttMove); int rangeReduction = 0; // Step 11. A small Probcut idea, when we are in check @@ -1124,18 +1122,9 @@ moves_loop: // When in check, search starts here else if (singularBeta >= beta) return singularBeta; - // If the eval of ttMove is greater than beta we try also if there is another - // move that pushes it over beta, if so the position also has probably multiple - // moves giving fail highs. We will then reduce the ttMove (negative extension). + // If the eval of ttMove is greater than beta, we reduce it (negative extension) else if (ttValue >= beta) - { - ss->excludedMove = move; - value = search(pos, ss, beta - 1, beta, (depth + 3) / 2, cutNode); - ss->excludedMove = MOVE_NONE; - - if (value >= beta) - extension = -2; - } + extension = -2; } // Capture extensions for PvNodes and cutNodes @@ -1187,11 +1176,9 @@ moves_loop: // When in check, search starts here { Depth r = reduction(improving, depth, moveCount, rangeReduction > 2); - if (PvNode) - r--; - - // Decrease reduction if the ttHit running average is large (~0 Elo) - if (thisThread->ttHitAverage.is_greater(537, 1024)) + // Decrease reduction if on the PV (~2 Elo) + if ( PvNode + && bestMoveCount <= 3) r--; // Decrease reduction if position is or has been on the PV @@ -1314,9 +1301,11 @@ moves_loop: // When in check, search starts here for (Move* m = (ss+1)->pv; *m != MOVE_NONE; ++m) rm.pv.push_back(*m); - // We record how often the best move has been changed in each - // iteration. This information is used for time management and LMR - if (moveCount > 1) + // We record how often the best move has been changed in each iteration. + // This information is used for time management and LMR. In MultiPV mode, + // we must take care to only do this for the first PV line. + if ( moveCount > 1 + && !thisThread->pvIdx) ++thisThread->bestMoveChanges; } else @@ -1338,7 +1327,10 @@ moves_loop: // When in check, search starts here update_pv(ss->pv, move, (ss+1)->pv); if (PvNode && value < beta) // Update alpha! Always alpha < beta + { alpha = value; + bestMoveCount++; + } else { assert(value >= beta); // Fail high @@ -1497,7 +1489,6 @@ moves_loop: // When in check, search starts here } else // In case of null move search use previous static eval with a different sign - // and addition of two tempos ss->staticEval = bestValue = (ss-1)->currentMove != MOVE_NULL ? evaluate(pos) : -(ss-1)->staticEval; @@ -1707,8 +1698,8 @@ moves_loop: // When in check, search starts here PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); bonus1 = stat_bonus(depth + 1); - bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus - : std::min(bonus1, stat_bonus(depth)); // smaller bonus + bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : stat_bonus(depth); // smaller bonus if (!pos.capture_or_promotion(bestMove)) {