X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=433129d9b5737659cacc8a9307d803a9a0e2d30d;hp=cb16798dc427fcc30162a9f346c0402aac680a95;hb=9da3b44ddc7bc9ea7094b91663cbc0f8319c46be;hpb=a6d6a2c2fad093a47b575ee4cfb8d346ba037fb3 diff --git a/src/search.cpp b/src/search.cpp index cb16798d..433129d9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -75,14 +75,17 @@ 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; } // History and stats update bonus, based on depth - Value stat_bonus(Depth depth) { + int stat_bonus(Depth depth) { int d = depth / ONE_PLY ; - return Value(d * d + 2 * d - 2); + return d > 17 ? 0 : d * d + 2 * d - 2; } // Skill structure is used to implement strength limit @@ -97,8 +100,8 @@ namespace { Move best = MOVE_NONE; }; - // EasyMoveManager structure is used to detect an 'easy move'. When the PV is - // stable across multiple search iterations, we can quickly return the best move. + // EasyMoveManager structure is used to detect an 'easy move'. When the PV is stable + // across multiple search iterations, we can quickly return the best move. struct EasyMoveManager { void clear() { @@ -148,8 +151,8 @@ namespace { Value value_to_tt(Value v, int ply); Value value_from_tt(Value v, int ply); void update_pv(Move* pv, Move move, Move* childPv); - void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus); - void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, Value bonus); + void update_cm_stats(Stack* ss, Piece pc, Square s, int bonus); + void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus); void check_time(); } // namespace @@ -163,7 +166,7 @@ void Search::init() { for (int d = 1; d < 64; ++d) for (int mc = 1; mc < 64; ++mc) { - double r = log(d) * log(mc) / 2; + double r = log(d) * log(mc) / 1.95; Reductions[NonPV][imp][d][mc] = int(std::round(r)); Reductions[PV][imp][d][mc] = std::max(Reductions[NonPV][imp][d][mc] - 1, 0); @@ -175,8 +178,8 @@ void Search::init() { for (int d = 0; d < 16; ++d) { - FutilityMoveCounts[0][d] = int(2.4 + 0.773 * pow(d + 0.00, 1.8)); - FutilityMoveCounts[1][d] = int(2.9 + 1.045 * pow(d + 0.49, 1.8)); + FutilityMoveCounts[0][d] = int(2.4 + 0.74 * pow(d, 1.78)); + FutilityMoveCounts[1][d] = int(5.0 + 1.00 * pow(d, 2.00)); } } @@ -192,6 +195,7 @@ void Search::clear() { th->counterMoves.clear(); th->history.clear(); th->counterMoveHistory.clear(); + th->counterMoveHistory[NO_PIECE][0].fill(CounterMovePruneThreshold-1); th->resetCalls = true; } @@ -542,7 +546,7 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval; bool ttHit, inCheck, givesCheck, singularExtensionNode, improving; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets; Piece moved_piece; int moveCount, quietCount; @@ -550,7 +554,7 @@ namespace { Thread* thisThread = pos.this_thread(); inCheck = pos.checkers(); moveCount = quietCount = ss->moveCount = 0; - ss->history = VALUE_ZERO; + ss->history = 0; bestValue = -VALUE_INFINITE; ss->ply = (ss-1)->ply + 1; @@ -635,7 +639,7 @@ namespace { // Penalty for a quiet ttMove that fails low else if (!pos.capture_or_promotion(ttMove)) { - Value penalty = -stat_bonus(depth + ONE_PLY); + int penalty = -stat_bonus(depth); thisThread->history.update(pos.side_to_move(), ttMove, penalty); update_cm_stats(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); } @@ -812,9 +816,6 @@ moves_loop: // When in check search starts from here const CounterMoveStats& cmh = *(ss-1)->counterMoves; const CounterMoveStats& fmh = *(ss-2)->counterMoves; const CounterMoveStats& fm2 = *(ss-4)->counterMoves; - const bool cm_ok = is_ok((ss-1)->currentMove); - const bool fm_ok = is_ok((ss-2)->currentMove); - const bool f2_ok = is_ok((ss-4)->currentMove); MovePicker mp(pos, ttMove, depth, ss); value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc @@ -829,10 +830,11 @@ moves_loop: // When in check search starts from here && !excludedMove // Recursive singular search is not allowed && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 3 * ONE_PLY; + skipQuiets = false; // Step 11. Loop through moves // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs - while ((move = mp.next_move()) != MOVE_NONE) + while ((move = mp.next_move(skipQuiets)) != MOVE_NONE) { assert(is_ok(move)); @@ -867,12 +869,7 @@ moves_loop: // When in check search starts from here moveCountPruning = depth < 16 * ONE_PLY && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY]; - // Step 12. Extensions - // Extend checks - if ( givesCheck - && !moveCountPruning - && pos.see_ge(move, VALUE_ZERO)) - extension = ONE_PLY; + // Step 12. Singular and Gives Check Extensions // Singular extension search. If all moves but one fail low on a search of // (alpha-s, beta-s), and just one fails high on (alpha, beta), then that move @@ -881,7 +878,6 @@ moves_loop: // When in check search starts from here // ttValue minus a margin then we extend the ttMove. if ( singularExtensionNode && move == ttMove - && !extension && pos.legal(move)) { Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE); @@ -893,12 +889,17 @@ moves_loop: // When in check search starts from here if (value < rBeta) extension = ONE_PLY; } + else if ( givesCheck + && !moveCountPruning + && pos.see_ge(move, VALUE_ZERO)) + extension = ONE_PLY; // Calculate new depth for this move newDepth = depth - ONE_PLY + extension; // Step 13. Pruning at shallow depth if ( !rootNode + && pos.non_pawn_material(pos.side_to_move()) && bestValue > VALUE_MATED_IN_MAX_PLY) { if ( !captureOrPromotion @@ -906,17 +907,18 @@ moves_loop: // When in check search starts from here && (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= 5000)) { // Move count based pruning - if (moveCountPruning) + if (moveCountPruning) { + skipQuiets = true; continue; + } // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY; // Countermoves based pruning if ( lmrDepth < 3 - && ((cmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !cm_ok) - && ((fmh[moved_piece][to_sq(move)] < VALUE_ZERO) || !fm_ok) - && ((fm2[moved_piece][to_sq(move)] < VALUE_ZERO) || !f2_ok || (cm_ok && fm_ok))) + && (cmh[moved_piece][to_sq(move)] < CounterMovePruneThreshold) + && (fmh[moved_piece][to_sq(move)] < CounterMovePruneThreshold)) continue; // Futility pruning: parent node @@ -983,10 +985,10 @@ moves_loop: // When in check search starts from here - 4000; // Correction factor // Decrease/increase reduction by comparing opponent's stat score - if (ss->history > VALUE_ZERO && (ss-1)->history < VALUE_ZERO) + if (ss->history > 0 && (ss-1)->history < 0) r -= ONE_PLY; - else if (ss->history < VALUE_ZERO && (ss-1)->history > VALUE_ZERO) + else if (ss->history < 0 && (ss-1)->history > 0) r += ONE_PLY; // Decrease/increase reduction for moves with a good/bad history @@ -1121,13 +1123,14 @@ moves_loop: // When in check search starts from here // Bonus for prior countermove that caused the fail low else if ( depth >= 3 * ONE_PLY && !pos.captured_piece() - && cm_ok) + && is_ok((ss-1)->currentMove)) update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth)); - tte->save(posKey, value_to_tt(bestValue, ss->ply), - bestValue >= beta ? BOUND_LOWER : - PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, - depth, bestMove, ss->staticEval, TT.generation()); + if(!excludedMove) + tte->save(posKey, value_to_tt(bestValue, ss->ply), + bestValue >= beta ? BOUND_LOWER : + PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, + depth, bestMove, ss->staticEval, TT.generation()); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); @@ -1379,7 +1382,7 @@ moves_loop: // When in check search starts from here // update_cm_stats() updates countermove and follow-up move history - void update_cm_stats(Stack* ss, Piece pc, Square s, Value bonus) { + void update_cm_stats(Stack* ss, Piece pc, Square s, int bonus) { for (int i : {1, 2, 4}) if (is_ok((ss-i)->currentMove)) @@ -1390,7 +1393,7 @@ moves_loop: // When in check search starts from here // update_stats() updates move sorting heuristics when a new quiet best move is found void update_stats(const Position& pos, Stack* ss, Move move, - Move* quiets, int quietsCnt, Value bonus) { + Move* quiets, int quietsCnt, int bonus) { if (ss->killers[0] != move) {