X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=b571cdf1787204e6c3e7c919da7c782de33439d4;hp=7e2df215ee8fb08b8030e6b449a53c16783dae56;hb=1725ed39adcc4aa6d96117a7b83e1552b37a6baa;hpb=80d59eea392fc073f6d0ba29cb9a97e3d705ee58 diff --git a/src/search.cpp b/src/search.cpp index 7e2df215..b571cdf1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -75,7 +75,7 @@ namespace { return (r + 520) / 1024 + (!i && r > 999); } - constexpr int futility_move_count(bool improving, int depth) { + constexpr int futility_move_count(bool improving, Depth depth) { return (5 + depth * depth) * (1 + improving) / 2; } @@ -153,8 +153,9 @@ namespace { Value value_from_tt(Value v, int ply); void update_pv(Move* pv, Move move, Move* childPv); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); - void update_quiet_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietCount, int bonus); - void update_capture_stats(const Position& pos, Move move, Move* captures, int captureCount, int bonus); + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); + void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); // perft() is our utility to verify move generation. All the leaf nodes up // to the given depth are generated and counted, and the sum is returned. @@ -417,7 +418,7 @@ void Thread::search() { beta = std::min(previousScore + delta, VALUE_INFINITE); // Adjust contempt based on root move's previousScore (dynamic contempt) - int dct = ct + 86 * previousScore / (abs(previousScore) + 176); + int dct = ct + (111 - ct / 2) * previousScore / (abs(previousScore) + 176); contempt = (us == WHITE ? make_score(dct, dct / 2) : -make_score(dct, dct / 2)); @@ -594,17 +595,17 @@ namespace { Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue; - bool ttHit, ttPv, inCheck, givesCheck, improving, doLMR, priorCapture; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; + bool ttHit, ttPv, inCheck, givesCheck, improving, didLMR, priorCapture; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture, singularLMR; Piece movedPiece; - int moveCount, captureCount, quietCount, singularLMR; + int moveCount, captureCount, quietCount; // Step 1. Initialize node Thread* thisThread = pos.this_thread(); inCheck = pos.checkers(); priorCapture = pos.captured_piece(); Color us = pos.side_to_move(); - moveCount = captureCount = quietCount = singularLMR = ss->moveCount = 0; + moveCount = captureCount = quietCount = ss->moveCount = 0; bestValue = -VALUE_INFINITE; maxValue = VALUE_INFINITE; @@ -679,7 +680,7 @@ namespace { if (ttValue >= beta) { if (!pos.capture_or_promotion(ttMove)) - update_quiet_stats(pos, ss, ttMove, nullptr, 0, stat_bonus(depth)); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -864,12 +865,17 @@ namespace { && probCutCount < 2 + 2 * cutNode) if (move != excludedMove && pos.legal(move)) { + assert(pos.capture_or_promotion(move)); + assert(depth >= 5); + + captureOrPromotion = true; probCutCount++; ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][pos.moved_piece(move)][to_sq(move)]; - - assert(depth >= 5); + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] + [pos.moved_piece(move)] + [to_sq(move)]; pos.do_move(move, st); @@ -900,8 +906,8 @@ namespace { moves_loop: // When in check, search starts from here const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, - nullptr, (ss-4)->continuationHistory, - nullptr, (ss-6)->continuationHistory }; + nullptr , (ss-4)->continuationHistory, + nullptr , (ss-6)->continuationHistory }; Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; @@ -911,8 +917,8 @@ moves_loop: // When in check, search starts from here countermove, ss->killers); - value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc - moveCountPruning = false; + value = bestValue; + singularLMR = moveCountPruning = false; ttCapture = ttMove && pos.capture_or_promotion(ttMove); // Mark this node as being searched @@ -975,10 +981,7 @@ moves_loop: // When in check, search starts from here if (value < singularBeta) { extension = 1; - singularLMR++; - - if (value < singularBeta - std::min(4 * depth, 36)) - singularLMR++; + singularLMR = true; } // Multi-cut pruning @@ -1068,7 +1071,10 @@ moves_loop: // When in check, search starts from here // Update the current move (this must be done after singular extension search) ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][movedPiece][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] + [movedPiece] + [to_sq(move)]; // Step 15. Make the move pos.do_move(move, st, givesCheck); @@ -1098,7 +1104,8 @@ moves_loop: // When in check, search starts from here r--; // Decrease reduction if ttMove has been singularly extended - r -= singularLMR; + if (singularLMR) + r -= 2; if (!captureOrPromotion) { @@ -1145,17 +1152,17 @@ moves_loop: // When in check, search starts from here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - doFullDepthSearch = (value > alpha && d != newDepth), doLMR = true; + doFullDepthSearch = (value > alpha && d != newDepth), didLMR = true; } else - doFullDepthSearch = !PvNode || moveCount > 1, doLMR = false; + doFullDepthSearch = !PvNode || moveCount > 1, didLMR = false; // Step 17. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) { value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); - if (doLMR && !captureOrPromotion) + if (didLMR && !captureOrPromotion) { int bonus = value > alpha ? stat_bonus(newDepth) : -stat_bonus(newDepth); @@ -1270,21 +1277,11 @@ moves_loop: // When in check, search starts from here if (!moveCount) bestValue = excludedMove ? alpha : inCheck ? mated_in(ss->ply) : VALUE_DRAW; - else if (bestMove) - { - // Quiet best move: update move sorting heuristics - if (!pos.capture_or_promotion(bestMove)) - update_quiet_stats(pos, ss, bestMove, quietsSearched, quietCount, - stat_bonus(depth + (bestValue > beta + PawnValueMg))); - - update_capture_stats(pos, bestMove, capturesSearched, captureCount, stat_bonus(depth + 1)); - // Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted - if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0])) - && !priorCapture) - update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); + else if (bestMove) + update_all_stats(pos, ss, bestMove, bestValue, beta, prevSq, + quietsSearched, quietCount, capturesSearched, captureCount, depth); - } // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) && !priorCapture) @@ -1323,7 +1320,7 @@ moves_loop: // When in check, search starts from here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; - bool ttHit, pvHit, inCheck, givesCheck, evasionPrunable, priorCapture; + bool ttHit, pvHit, inCheck, givesCheck, captureOrPromotion, evasionPrunable; int moveCount; if (PvNode) @@ -1337,7 +1334,6 @@ moves_loop: // When in check, search starts from here (ss+1)->ply = ss->ply + 1; bestMove = MOVE_NONE; inCheck = pos.checkers(); - priorCapture = pos.captured_piece(); moveCount = 0; // Check for an immediate draw or maximum ply reached @@ -1408,8 +1404,8 @@ moves_loop: // When in check, search starts from here } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, - nullptr, (ss-4)->continuationHistory, - nullptr, (ss-6)->continuationHistory }; + nullptr , (ss-4)->continuationHistory, + nullptr , (ss-6)->continuationHistory }; // Initialize a MovePicker object for the current position, and prepare // to search the moves. Because the depth is <= 0 here, only captures, @@ -1426,6 +1422,7 @@ moves_loop: // When in check, search starts from here assert(is_ok(move)); givesCheck = pos.gives_check(move); + captureOrPromotion = pos.capture_or_promotion(move); moveCount++; @@ -1460,7 +1457,7 @@ moves_loop: // When in check, search starts from here // Don't search moves with negative SEE values if ( (!inCheck || evasionPrunable) - && (!givesCheck || !(pos.blockers_for_king(~pos.side_to_move()) & from_sq(move))) + && !(givesCheck && pos.is_discovery_check_on_king(~pos.side_to_move(), move)) && !pos.see_ge(move)) continue; @@ -1475,7 +1472,10 @@ moves_loop: // When in check, search starts from here } ss->currentMove = move; - ss->continuationHistory = &thisThread->continuationHistory[inCheck][priorCapture][pos.moved_piece(move)][to_sq(move)]; + ss->continuationHistory = &thisThread->continuationHistory[inCheck] + [captureOrPromotion] + [pos.moved_piece(move)] + [to_sq(move)]; // Make and search the move pos.do_move(move, st, givesCheck); @@ -1555,43 +1555,65 @@ moves_loop: // When in check, search starts from here } - // update_continuation_histories() updates histories of the move pairs formed - // by moves at ply -1, -2, and -4 with current move. + // update_all_stats() updates stats at the end of search() when a bestMove is found - void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { + void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, + Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth) { - for (int i : {1, 2, 4, 6}) - if (is_ok((ss-i)->currentMove)) - (*(ss-i)->continuationHistory)[pc][to] << bonus; - } + int bonus1, bonus2; + Color us = pos.side_to_move(); + Thread* thisThread = pos.this_thread(); + CapturePieceToHistory& captureHistory = thisThread->captureHistory; + Piece moved_piece = pos.moved_piece(bestMove); + PieceType captured = type_of(pos.piece_on(to_sq(bestMove))); + bonus1 = stat_bonus(depth + 1); + bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus + : stat_bonus(depth); // smaller bonus - // update_capture_stats() updates move sorting heuristics when a new capture best move is found + if (!pos.capture_or_promotion(bestMove)) + { + update_quiet_stats(pos, ss, bestMove, bonus2); - void update_capture_stats(const Position& pos, Move move, - Move* captures, int captureCount, int bonus) { + // Decrease all the non-best quiet moves + for (int i = 0; i < quietCount; ++i) + { + thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bonus2; + update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]), to_sq(quietsSearched[i]), -bonus2); + } + } + else + captureHistory[moved_piece][to_sq(bestMove)][captured] << bonus1; - CapturePieceToHistory& captureHistory = pos.this_thread()->captureHistory; - Piece moved_piece = pos.moved_piece(move); - PieceType captured = type_of(pos.piece_on(to_sq(move))); + // Extra penalty for a quiet TT or main killer move in previous ply when it gets refuted + if ( ((ss-1)->moveCount == 1 || ((ss-1)->currentMove == (ss-1)->killers[0])) + && !pos.captured_piece()) + update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -bonus1); - if (pos.capture_or_promotion(move)) - captureHistory[moved_piece][to_sq(move)][captured] << bonus; + // Decrease all the non-best capture moves + for (int i = 0; i < captureCount; ++i) + { + moved_piece = pos.moved_piece(capturesSearched[i]); + captured = type_of(pos.piece_on(to_sq(capturesSearched[i]))); + captureHistory[moved_piece][to_sq(capturesSearched[i])][captured] << -bonus1; + } + } - // Decrease all the other played capture moves - for (int i = 0; i < captureCount; ++i) - { - moved_piece = pos.moved_piece(captures[i]); - captured = type_of(pos.piece_on(to_sq(captures[i]))); - captureHistory[moved_piece][to_sq(captures[i])][captured] << -bonus; - } + + // update_continuation_histories() updates histories of the move pairs formed + // by moves at ply -1, -2, and -4 with current move. + + void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { + + for (int i : {1, 2, 4, 6}) + if (is_ok((ss-i)->currentMove)) + (*(ss-i)->continuationHistory)[pc][to] << bonus; } - // update_quiet_stats() updates move sorting heuristics when a new quiet best move is found + // update_quiet_stats() updates move sorting heuristics - void update_quiet_stats(const Position& pos, Stack* ss, Move move, - Move* quiets, int quietCount, int bonus) { + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) { if (ss->killers[0] != move) { @@ -1612,13 +1634,6 @@ moves_loop: // When in check, search starts from here Square prevSq = to_sq((ss-1)->currentMove); thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move; } - - // Decrease all the other played quiet moves - for (int i = 0; i < quietCount; ++i) - { - thisThread->mainHistory[us][from_to(quiets[i])] << -bonus; - update_continuation_histories(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); - } } // When playing with strength handicap, choose best move among a set of RootMoves