X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=b75870ff5021968f66d0e0a0aa02271a310cec00;hp=a17a7506856bf82f36d5dbf47f3e55694e6fa22b;hb=5254a6040c59cf7d3b9faa847168ccbd628c0574;hpb=f72b7dc99af07c4f012ef229f9d3dcc490d6d69f diff --git a/src/search.cpp b/src/search.cpp index a17a7506..b75870ff 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -2,7 +2,7 @@ Stockfish, a UCI chess playing engine derived from Glaurung 2.1 Copyright (C) 2004-2008 Tord Romstad (Glaurung author) Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad - Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad + Copyright (C) 2015-2017 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -75,6 +75,12 @@ namespace { 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 d = depth / ONE_PLY ; + return Value(d * d + 2 * d - 2); + } + // Skill structure is used to implement strength limit struct Skill { Skill(int l) : level(l) {} @@ -153,9 +159,6 @@ namespace { {1, 0, 0, 0, 0, 1, 1 ,1}, }; - Value bonus(Depth depth) { int d = depth / ONE_PLY ; return Value(d * d + 2 * d - 2); } - Value penalty(Depth depth) { int d = depth / ONE_PLY ; return -Value(d * d + 4 * d + 1); } - const size_t HalfDensitySize = std::extent::value; EasyMoveManager EasyMove; @@ -211,9 +214,8 @@ void Search::clear() { for (Thread* th : Threads) { - th->history.clear(); th->counterMoves.clear(); - th->fromTo.clear(); + th->history.clear(); th->counterMoveHistory.clear(); th->resetCalls = true; } @@ -312,9 +314,13 @@ void MainThread::search() { && rootMoves[0].pv[0] != MOVE_NONE) { for (Thread* th : Threads) - if ( th->completedDepth > bestThread->completedDepth - && th->rootMoves[0].score > bestThread->rootMoves[0].score) + { + Depth depthDiff = th->completedDepth - bestThread->completedDepth; + Value scoreDiff = th->rootMoves[0].score - bestThread->rootMoves[0].score; + + if (scoreDiff > 0 && depthDiff >= 0) bestThread = th; + } } previousScore = bestThread->rootMoves[0].score; @@ -597,7 +603,7 @@ namespace { if (!rootNode) { // Step 2. Check for aborted search and immediate draw - if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw() || ss->ply >= MAX_PLY) + if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos) : DrawValue[pos.side_to_move()]; @@ -638,15 +644,25 @@ namespace { && (ttValue >= beta ? (tte->bound() & BOUND_LOWER) : (tte->bound() & BOUND_UPPER))) { - // If ttMove is quiet, update killers, history, counter move on TT hit - if (ttValue >= beta && ttMove) + // If ttMove is quiet, update move sorting heuristics on TT hit + if (ttMove) { - if (!pos.capture_or_promotion(ttMove)) - update_stats(pos, ss, ttMove, nullptr, 0, bonus(depth)); + if (ttValue >= beta) + { + if (!pos.capture_or_promotion(ttMove)) + update_stats(pos, ss, ttMove, nullptr, 0, stat_bonus(depth)); - // Extra penalty for a quiet TT move in previous ply when it gets refuted - if ((ss-1)->moveCount == 1 && !pos.captured_piece()) - update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, penalty(depth)); + // Extra penalty for a quiet TT move in previous ply when it gets refuted + if ((ss-1)->moveCount == 1 && !pos.captured_piece()) + update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); + } + // Penalty for a quiet ttMove that fails low + else if (ttValue < alpha && !pos.capture_or_promotion(ttMove)) + { + Value penalty = -stat_bonus(depth + ONE_PLY); + thisThread->history.update(pos.side_to_move(), ttMove, penalty); + update_cm_stats(ss, pos.moved_piece(ttMove), to_sq(ttMove), penalty); + } } return ttValue; } @@ -721,7 +737,7 @@ namespace { && eval + razor_margin[depth / ONE_PLY] <= alpha) { if (depth <= ONE_PLY) - return qsearch(pos, ss, alpha, beta); + return qsearch(pos, ss, alpha, alpha+1); Value ralpha = alpha - razor_margin[depth / ONE_PLY]; Value v = qsearch(pos, ss, ralpha, ralpha+1); @@ -872,7 +888,8 @@ moves_loop: // When in check search starts from here moveCountPruning = depth < 16 * ONE_PLY && moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY]; - // Step 12. Extend checks + // Step 12. Extensions + // Extend checks if ( givesCheck && !moveCountPruning && pos.see_ge(move, VALUE_ZERO)) @@ -898,7 +915,7 @@ moves_loop: // When in check search starts from here extension = ONE_PLY; } - // Update the current move (this must be done after singular extension search) + // Calculate new depth for this move newDepth = depth - ONE_PLY + extension; // Step 13. Pruning at shallow depth @@ -950,6 +967,7 @@ moves_loop: // When in check search starts from here continue; } + // Update the current move (this must be done after singular extension search) ss->currentMove = move; ss->counterMoves = &thisThread->counterMoveHistory[moved_piece][to_sq(move)]; @@ -979,12 +997,11 @@ moves_loop: // When in check search starts from here && !pos.see_ge(make_move(to_sq(move), from_sq(move)), VALUE_ZERO)) r -= 2 * ONE_PLY; - ss->history = 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) - - 8000; // Correction factor + ss->history = (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->history.get(~pos.side_to_move(), move) + - 4000; // Correction factor // Decrease/increase reduction by comparing opponent's stat score if (ss->history > VALUE_ZERO && (ss-1)->history < VALUE_ZERO) @@ -1074,13 +1091,6 @@ moves_loop: // When in check search starts from here if (value > alpha) { - // If there is an easy move for this position, clear it if unstable - if ( PvNode - && thisThread == Threads.main() - && EasyMove.get(pos.key()) - && (move != EasyMove.get(pos.key()) || moveCount > 1)) - EasyMove.clear(); - bestMove = move; if (PvNode && !rootNode) // Update pv even in fail-high case @@ -1121,19 +1131,19 @@ moves_loop: // When in check search starts from here else if (bestMove) { - // Quiet best move: update killers, history and countermoves + // Quiet best move: update move sorting heuristics if (!pos.capture_or_promotion(bestMove)) - update_stats(pos, ss, bestMove, quietsSearched, quietCount, bonus(depth)); + update_stats(pos, ss, bestMove, quietsSearched, quietCount, stat_bonus(depth)); // Extra penalty for a quiet TT move in previous ply when it gets refuted if ((ss-1)->moveCount == 1 && !pos.captured_piece()) - update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, penalty(depth)); + update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + ONE_PLY)); } // Bonus for prior countermove that caused the fail low else if ( depth >= 3 * ONE_PLY && !pos.captured_piece() && is_ok((ss-1)->currentMove)) - update_cm_stats(ss-1, pos.piece_on(prevSq), prevSq, bonus(depth)); + 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 : @@ -1180,7 +1190,7 @@ moves_loop: // When in check search starts from here ss->ply = (ss-1)->ply + 1; // Check for an instant draw or if the maximum ply has been reached - if (pos.is_draw() || ss->ply >= MAX_PLY) + if (pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) return ss->ply >= MAX_PLY && !InCheck ? evaluate(pos) : DrawValue[pos.side_to_move()]; @@ -1407,8 +1417,7 @@ moves_loop: // When in check search starts from here } - // update_stats() updates killers, history, countermove and countermove plus - // follow-up move history when a new quiet best move is found. + // 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) { @@ -1421,8 +1430,7 @@ moves_loop: // When in check search starts from here Color c = pos.side_to_move(); Thread* thisThread = pos.this_thread(); - thisThread->fromTo.update(c, move, bonus); - thisThread->history.update(pos.moved_piece(move), to_sq(move), bonus); + thisThread->history.update(c, move, bonus); update_cm_stats(ss, pos.moved_piece(move), to_sq(move), bonus); if ((ss-1)->counterMoves) @@ -1434,8 +1442,7 @@ moves_loop: // When in check search starts from here // Decrease all the other played quiet moves for (int i = 0; i < quietsCnt; ++i) { - thisThread->fromTo.update(c, quiets[i], -bonus); - thisThread->history.update(pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); + thisThread->history.update(c, quiets[i], -bonus); update_cm_stats(ss, pos.moved_piece(quiets[i]), to_sq(quiets[i]), -bonus); } }