X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsearch.cpp;h=15f08859f8e3f105e435d24aff1d534b083da6f5;hb=0b4f6e562b76a7a7fb581ad117927748371fe790;hp=a81c85273aa4e6325e103dcd1d7ec1afc2636054;hpb=f2f3a06a1acfa14b3054bfd73d6c3966c326a7cc;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index a81c8527..15f08859 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -65,7 +65,7 @@ namespace { // Razoring and futility margin based on depth const int razor_margin[4] = { 483, 570, 603, 554 }; - Value futility_margin(Depth d) { return Value(200 * d); } + Value futility_margin(Depth d) { return Value(150 * d); } // Futility and reductions lookup tables, initialized at startup int FutilityMoveCounts[2][16]; // [improving][depth] @@ -213,6 +213,7 @@ void Search::clear() { { th->history.clear(); th->counterMoves.clear(); + th->fromTo.clear(); } Threads.main()->previousScore = VALUE_INFINITE; @@ -635,7 +636,7 @@ namespace { ss->currentMove = ttMove; // Can be MOVE_NONE // If ttMove is quiet, update killers, history, counter move on TT hit - if (ttValue >= beta && ttMove && !pos.capture_or_promotion(ttMove)) + if (ttValue >= beta && ttMove) update_stats(pos, ss, ttMove, depth, nullptr, 0); return ttValue; @@ -800,13 +801,12 @@ namespace { } // Step 10. Internal iterative deepening (skipped when in check) - if ( depth >= (PvNode ? 5 * ONE_PLY : 8 * ONE_PLY) + if ( depth >= 6 * ONE_PLY && !ttMove && (PvNode || ss->staticEval + 256 >= beta)) { - Depth d = depth - 2 * ONE_PLY - (PvNode ? DEPTH_ZERO : depth / 4); ss->skipEarlyPruning = true; - search(pos, ss, alpha, beta, d, cutNode); + search(pos, ss, alpha, beta, 3 * depth / 4 - 2 * ONE_PLY, cutNode); ss->skipEarlyPruning = false; tte = TT.probe(posKey, ttHit); @@ -914,19 +914,19 @@ moves_loop: // When in check search starts from here if (moveCountPruning) continue; + predictedDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO); + // Countermoves based pruning - if ( depth <= 4 * ONE_PLY + if ( predictedDepth < 3 * ONE_PLY && move != ss->killers[0] && (!cmh || (*cmh )[moved_piece][to_sq(move)] < VALUE_ZERO) && (!fmh || (*fmh )[moved_piece][to_sq(move)] < VALUE_ZERO) && (!fmh2 || (*fmh2)[moved_piece][to_sq(move)] < VALUE_ZERO || (cmh && fmh))) continue; - predictedDepth = std::max(newDepth - reduction(improving, depth, moveCount), DEPTH_ZERO); - // Futility pruning: parent node if ( predictedDepth < 7 * ONE_PLY - && ss->staticEval + futility_margin(predictedDepth) + 256 <= alpha) + && ss->staticEval + 256 + 200 * predictedDepth / ONE_PLY <= alpha) continue; // Prune moves with negative SEE at low depths and below a decreasing @@ -961,36 +961,43 @@ moves_loop: // When in check search starts from here // re-searched at full depth. if ( depth >= 3 * ONE_PLY && moveCount > 1 - && !captureOrPromotion) + && (!captureOrPromotion || moveCountPruning)) { Depth r = reduction(improving, depth, moveCount); - Value val = thisThread->history[moved_piece][to_sq(move)] - + (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO) - + (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO) - + (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO); - - // Increase reduction for cut nodes - if (cutNode) - r += 2 * ONE_PLY; - - // Decrease reduction for moves that escape a capture. Filter out - // castling moves, because they are coded as "king captures rook" and - // hence break make_move(). Also use see() instead of see_sign(), - // because the destination square is empty. - else if ( type_of(move) == NORMAL - && type_of(pos.piece_on(to_sq(move))) != PAWN - && pos.see(make_move(to_sq(move), from_sq(move))) < VALUE_ZERO) - r -= 2 * ONE_PLY; - - // Decrease/increase reduction for moves with a good/bad history - int rHist = (val - 10000) / 20000; - r = std::max(DEPTH_ZERO, r - rHist * ONE_PLY); + + if (captureOrPromotion) + r -= r ? ONE_PLY : DEPTH_ZERO; + else + { + Value val = thisThread->history[moved_piece][to_sq(move)] + + (cmh ? (*cmh )[moved_piece][to_sq(move)] : VALUE_ZERO) + + (fmh ? (*fmh )[moved_piece][to_sq(move)] : VALUE_ZERO) + + (fmh2 ? (*fmh2)[moved_piece][to_sq(move)] : VALUE_ZERO) + + thisThread->fromTo.get(~pos.side_to_move(), move); + + // Increase reduction for cut nodes + if (cutNode) + r += 2 * ONE_PLY; + + // Decrease reduction for moves that escape a capture. Filter out + // castling moves, because they are coded as "king captures rook" and + // hence break make_move(). Also use see() instead of see_sign(), + // because the destination square is empty. + else if ( type_of(move) == NORMAL + && type_of(pos.piece_on(to_sq(move))) != PAWN + && pos.see(make_move(to_sq(move), from_sq(move))) < VALUE_ZERO) + r -= 2 * ONE_PLY; + + // Decrease/increase reduction for moves with a good/bad history + int rHist = (val - 8000) / 20000; + r = std::max(DEPTH_ZERO, r - rHist * ONE_PLY); + } Depth d = std::max(newDepth - r, ONE_PLY); value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - doFullDepthSearch = (value > alpha && r != DEPTH_ZERO); + doFullDepthSearch = (value > alpha && d != newDepth); } else doFullDepthSearch = !PvNode || moveCount > 1; @@ -1106,12 +1113,11 @@ moves_loop: // When in check search starts from here : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; // Quiet best move: update killers, history and countermoves - else if (bestMove && !pos.capture_or_promotion(bestMove)) + else if (bestMove) update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount); // Bonus for prior countermove that caused the fail low else if ( depth >= 3 * ONE_PLY - && !bestMove && !pos.captured_piece_type() && is_ok((ss-1)->currentMove)) { @@ -1390,21 +1396,43 @@ moves_loop: // When in check search starts from here void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt) { + Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + 2 * depth / ONE_PLY - 2); + Square prevSq = to_sq((ss-1)->currentMove); + + // Extra penalty for a quiet TT move in previous ply when it gets refuted + if ((ss-1)->moveCount == 1 && !pos.captured_piece_type()) + { + CounterMoveStats* fmh = (ss-2)->counterMoves; + CounterMoveStats* cmh2 = (ss-3)->counterMoves; + CounterMoveStats* cmh3 = (ss-5)->counterMoves; + + if (fmh) + fmh->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1); + + if (cmh2) + cmh2->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1); + + if (cmh3) + cmh3->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1); + } + + if (pos.capture_or_promotion(move)) + return; + if (ss->killers[0] != move) { ss->killers[1] = ss->killers[0]; ss->killers[0] = move; } - Value bonus = Value((depth / ONE_PLY) * (depth / ONE_PLY) + 2 * depth / ONE_PLY - 2); - - Square prevSq = to_sq((ss-1)->currentMove); CounterMoveStats* cmh = (ss-1)->counterMoves; CounterMoveStats* fmh = (ss-2)->counterMoves; CounterMoveStats* fmh2 = (ss-4)->counterMoves; + Color c = pos.side_to_move(); Thread* thisThread = pos.this_thread(); thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus); + thisThread->fromTo.update(c, move, bonus); if (cmh) { @@ -1422,6 +1450,7 @@ moves_loop: // When in check search starts from here for (int i = 0; i < quietsCnt; ++i) { thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); + thisThread->fromTo.update(c, quiets[i], -bonus); if (cmh) cmh->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); @@ -1432,19 +1461,6 @@ moves_loop: // When in check search starts from here if (fmh2) fmh2->update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); } - - // Extra penalty for a quiet TT move in previous ply when it gets refuted - if ((ss-1)->moveCount == 1 && !pos.captured_piece_type()) - { - if ((ss-2)->counterMoves) - (ss-2)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1); - - if ((ss-3)->counterMoves) - (ss-3)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1); - - if ((ss-5)->counterMoves) - (ss-5)->counterMoves->update(pos.piece_on(prevSq), prevSq, -bonus - 2 * (depth + 1) / ONE_PLY - 1); - } }