mirror of
https://github.com/sockspls/badfish
synced 2025-05-01 01:03:09 +00:00
Rewrite search best value update
A simplification and also a small speed-up of about 1% mainly due to reducing calls to thisThread->cutoff_occurred(). Worst case split point recovering time after a cut-off occurred is limited to 3 msec on my slow PC, and usually is below 1 msec, so it seems safe to remove the cutoff_occurred() check. No functional change.
This commit is contained in:
parent
c9f9262a49
commit
d471c49700
1 changed files with 29 additions and 35 deletions
|
@ -55,6 +55,9 @@ namespace {
|
||||||
// Set to true to force running with one thread. Used for debugging
|
// Set to true to force running with one thread. Used for debugging
|
||||||
const bool FakeSplit = false;
|
const bool FakeSplit = false;
|
||||||
|
|
||||||
|
// This is the minimum interval in msec between two check_time() calls
|
||||||
|
const int TimerResolution = 5;
|
||||||
|
|
||||||
// Different node types, used as template parameter
|
// Different node types, used as template parameter
|
||||||
enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV };
|
enum NodeType { Root, PV, NonPV, SplitPointRoot, SplitPointPV, SplitPointNonPV };
|
||||||
|
|
||||||
|
@ -88,10 +91,6 @@ namespace {
|
||||||
return (Depth) Reductions[PvNode][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)];
|
return (Depth) Reductions[PvNode][std::min(int(d) / ONE_PLY, 63)][std::min(mn, 63)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the minimum interval in msec between two check_time() calls
|
|
||||||
const int TimerResolution = 5;
|
|
||||||
|
|
||||||
|
|
||||||
size_t MultiPV, UCIMultiPV, PVIdx;
|
size_t MultiPV, UCIMultiPV, PVIdx;
|
||||||
TimeManager TimeMgr;
|
TimeManager TimeMgr;
|
||||||
int BestMoveChanges;
|
int BestMoveChanges;
|
||||||
|
@ -99,7 +98,6 @@ namespace {
|
||||||
bool SkillLevelEnabled, Chess960;
|
bool SkillLevelEnabled, Chess960;
|
||||||
History H;
|
History H;
|
||||||
|
|
||||||
|
|
||||||
template <NodeType NT>
|
template <NodeType NT>
|
||||||
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
|
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth);
|
||||||
|
|
||||||
|
@ -505,7 +503,7 @@ namespace {
|
||||||
Key posKey;
|
Key posKey;
|
||||||
Move ttMove, move, excludedMove, bestMove, threatMove;
|
Move ttMove, move, excludedMove, bestMove, threatMove;
|
||||||
Depth ext, newDepth;
|
Depth ext, newDepth;
|
||||||
Value bestValue, value, oldAlpha, ttValue;
|
Value bestValue, value, ttValue;
|
||||||
Value refinedValue, nullValue, futilityValue;
|
Value refinedValue, nullValue, futilityValue;
|
||||||
bool pvMove, inCheck, singularExtensionNode, givesCheck;
|
bool pvMove, inCheck, singularExtensionNode, givesCheck;
|
||||||
bool captureOrPromotion, dangerous, doFullDepthSearch;
|
bool captureOrPromotion, dangerous, doFullDepthSearch;
|
||||||
|
@ -514,7 +512,6 @@ namespace {
|
||||||
// Step 1. Initialize node
|
// Step 1. Initialize node
|
||||||
Thread* thisThread = pos.this_thread();
|
Thread* thisThread = pos.this_thread();
|
||||||
moveCount = playedMoveCount = 0;
|
moveCount = playedMoveCount = 0;
|
||||||
oldAlpha = alpha;
|
|
||||||
inCheck = pos.in_check();
|
inCheck = pos.in_check();
|
||||||
|
|
||||||
if (SpNode)
|
if (SpNode)
|
||||||
|
@ -771,10 +768,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
|
|
||||||
// Step 11. Loop through moves
|
// Step 11. Loop through moves
|
||||||
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
|
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
|
||||||
while ( bestValue < beta
|
while (bestValue < beta && (move = mp.next_move<SpNode>()) != MOVE_NONE)
|
||||||
&& (move = mp.next_move<SpNode>()) != MOVE_NONE
|
|
||||||
&& !thisThread->cutoff_occurred()
|
|
||||||
&& !Signals.stop)
|
|
||||||
{
|
{
|
||||||
assert(is_ok(move));
|
assert(is_ok(move));
|
||||||
|
|
||||||
|
@ -958,7 +952,10 @@ split_point_start: // At split points actual search starts from here
|
||||||
// was aborted because the user interrupted the search or because we
|
// was aborted because the user interrupted the search or because we
|
||||||
// ran out of time. In this case, the return value of the search cannot
|
// ran out of time. In this case, the return value of the search cannot
|
||||||
// be trusted, and we don't update the best move and/or PV.
|
// be trusted, and we don't update the best move and/or PV.
|
||||||
if (RootNode && !Signals.stop)
|
if (Signals.stop || thisThread->cutoff_occurred())
|
||||||
|
return bestValue;
|
||||||
|
|
||||||
|
if (RootNode)
|
||||||
{
|
{
|
||||||
RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move);
|
RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move);
|
||||||
|
|
||||||
|
@ -984,16 +981,16 @@ split_point_start: // At split points actual search starts from here
|
||||||
if (value > bestValue)
|
if (value > bestValue)
|
||||||
{
|
{
|
||||||
bestValue = value;
|
bestValue = value;
|
||||||
bestMove = move;
|
|
||||||
|
|
||||||
if ( PvNode
|
if (value > alpha)
|
||||||
&& value > alpha
|
|
||||||
&& value < beta) // We want always alpha < beta
|
|
||||||
{
|
{
|
||||||
alpha = bestValue; // Update alpha here!
|
bestMove = move;
|
||||||
|
|
||||||
|
if (PvNode && value < beta)
|
||||||
|
alpha = bestValue; // Update alpha here! Always alpha < beta
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SpNode && !thisThread->cutoff_occurred())
|
if (SpNode)
|
||||||
{
|
{
|
||||||
sp->bestValue = bestValue;
|
sp->bestValue = bestValue;
|
||||||
sp->bestMove = bestMove;
|
sp->bestMove = bestMove;
|
||||||
|
@ -1004,17 +1001,18 @@ split_point_start: // At split points actual search starts from here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 19. Check for split
|
// Step 19. Check for splitting the search
|
||||||
if ( !SpNode
|
if ( !SpNode
|
||||||
&& depth >= Threads.min_split_depth()
|
&& depth >= Threads.min_split_depth()
|
||||||
&& bestValue < beta
|
&& bestValue < beta
|
||||||
&& Threads.available_slave_exists(thisThread)
|
&& Threads.available_slave_exists(thisThread))
|
||||||
&& !Signals.stop
|
|
||||||
&& !thisThread->cutoff_occurred())
|
|
||||||
bestValue = Threads.split<FakeSplit>(pos, ss, alpha, beta, bestValue, &bestMove,
|
bestValue = Threads.split<FakeSplit>(pos, ss, alpha, beta, bestValue, &bestMove,
|
||||||
depth, threatMove, moveCount, mp, NT);
|
depth, threatMove, moveCount, mp, NT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SpNode)
|
||||||
|
return bestValue;
|
||||||
|
|
||||||
// Step 20. Check for mate and stalemate
|
// Step 20. Check for mate and stalemate
|
||||||
// All legal moves have been searched and if there are no legal moves, it
|
// All legal moves have been searched and if there are no legal moves, it
|
||||||
// must be mate or stalemate. Note that we can have a false positive in
|
// must be mate or stalemate. Note that we can have a false positive in
|
||||||
|
@ -1022,7 +1020,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
// harmless because return value is discarded anyhow in the parent nodes.
|
// harmless because return value is discarded anyhow in the parent nodes.
|
||||||
// If we are in a singular extension search then return a fail low score.
|
// If we are in a singular extension search then return a fail low score.
|
||||||
// A split node has at least one move, the one tried before to be splitted.
|
// A split node has at least one move, the one tried before to be splitted.
|
||||||
if (!SpNode && !moveCount)
|
if (!moveCount)
|
||||||
return excludedMove ? alpha : inCheck ? mated_in(ss->ply) : VALUE_DRAW;
|
return excludedMove ? alpha : inCheck ? mated_in(ss->ply) : VALUE_DRAW;
|
||||||
|
|
||||||
// If we have pruned all the moves without searching return a fail-low score
|
// If we have pruned all the moves without searching return a fail-low score
|
||||||
|
@ -1033,20 +1031,12 @@ split_point_start: // At split points actual search starts from here
|
||||||
bestValue = alpha;
|
bestValue = alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 21. Update tables
|
if (bestValue >= beta) // Failed high
|
||||||
// Update transposition table entry, killers and history
|
|
||||||
if (!SpNode && !Signals.stop && !thisThread->cutoff_occurred())
|
|
||||||
{
|
{
|
||||||
Move ttm = bestValue <= oldAlpha ? MOVE_NONE : bestMove;
|
TT.store(posKey, value_to_tt(bestValue, ss->ply), BOUND_LOWER, depth,
|
||||||
Bound bt = bestValue <= oldAlpha ? BOUND_UPPER
|
bestMove, ss->eval, ss->evalMargin);
|
||||||
: bestValue >= beta ? BOUND_LOWER : BOUND_EXACT;
|
|
||||||
|
|
||||||
TT.store(posKey, value_to_tt(bestValue, ss->ply), bt, depth, ttm, ss->eval, ss->evalMargin);
|
if (!pos.is_capture_or_promotion(bestMove) && !inCheck)
|
||||||
|
|
||||||
// Update killers and history for non capture cut-off moves
|
|
||||||
if ( bestValue >= beta
|
|
||||||
&& !pos.is_capture_or_promotion(bestMove)
|
|
||||||
&& !inCheck)
|
|
||||||
{
|
{
|
||||||
if (bestMove != ss->killers[0])
|
if (bestMove != ss->killers[0])
|
||||||
{
|
{
|
||||||
|
@ -1066,6 +1056,10 @@ split_point_start: // At split points actual search starts from here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // Failed low or PV search
|
||||||
|
TT.store(posKey, value_to_tt(bestValue, ss->ply),
|
||||||
|
PvNode && bestMove != MOVE_NONE ? BOUND_EXACT : BOUND_UPPER,
|
||||||
|
depth, bestMove, ss->eval, ss->evalMargin);
|
||||||
|
|
||||||
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue