mirror of
https://github.com/sockspls/badfish
synced 2025-05-01 09:13:08 +00:00
Cleanup and reorder in qsearch
This patch is a simplification / code normalisation in qsearch. Adds steps in comments the same way we have in search; Makes a separate "pruning" stage instead of heuristics randomly being spread over qsearch code; Reorders pruning heuristics from least taxing ones to more taxing ones; Removes repeated check for best value not being mated, instead uses 1 check - thus removes some lines of code. Moves prefetch and move setup after pruning - makes no sense to do them if move will actually get pruned. Passed non-regression test: https://tests.stockfishchess.org/tests/view/63dd2c5ff9a50a69252c1413 LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 113504 W: 29898 L: 29770 D: 53836 Ptnml(0-2): 287, 11861, 32327, 11991, 286 https://github.com/official-stockfish/Stockfish/pull/4382 Non-functional change.
This commit is contained in:
parent
d5817a5896
commit
8f843633db
1 changed files with 30 additions and 24 deletions
|
@ -1427,6 +1427,7 @@ moves_loop: // When in check, search starts here
|
||||||
bool pvHit, givesCheck, capture;
|
bool pvHit, givesCheck, capture;
|
||||||
int moveCount;
|
int moveCount;
|
||||||
|
|
||||||
|
// Step 1. Initialize node
|
||||||
if (PvNode)
|
if (PvNode)
|
||||||
{
|
{
|
||||||
(ss+1)->pv = pv;
|
(ss+1)->pv = pv;
|
||||||
|
@ -1438,7 +1439,7 @@ moves_loop: // When in check, search starts here
|
||||||
ss->inCheck = pos.checkers();
|
ss->inCheck = pos.checkers();
|
||||||
moveCount = 0;
|
moveCount = 0;
|
||||||
|
|
||||||
// Check for an immediate draw or maximum ply reached
|
// Step 2. Check for an immediate draw or maximum ply reached
|
||||||
if ( pos.is_draw(ss->ply)
|
if ( pos.is_draw(ss->ply)
|
||||||
|| ss->ply >= MAX_PLY)
|
|| ss->ply >= MAX_PLY)
|
||||||
return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : VALUE_DRAW;
|
return (ss->ply >= MAX_PLY && !ss->inCheck) ? evaluate(pos) : VALUE_DRAW;
|
||||||
|
@ -1450,13 +1451,14 @@ moves_loop: // When in check, search starts here
|
||||||
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
|
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
|
||||||
ttDepth = ss->inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
|
ttDepth = ss->inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
|
||||||
: DEPTH_QS_NO_CHECKS;
|
: DEPTH_QS_NO_CHECKS;
|
||||||
// Transposition table lookup
|
// Step 3. Transposition table lookup
|
||||||
posKey = pos.key();
|
posKey = pos.key();
|
||||||
tte = TT.probe(posKey, ss->ttHit);
|
tte = TT.probe(posKey, ss->ttHit);
|
||||||
ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
|
ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
|
||||||
ttMove = ss->ttHit ? tte->move() : MOVE_NONE;
|
ttMove = ss->ttHit ? tte->move() : MOVE_NONE;
|
||||||
pvHit = ss->ttHit && tte->is_pv();
|
pvHit = ss->ttHit && tte->is_pv();
|
||||||
|
|
||||||
|
// At non-PV nodes we check for an early TT cutoff
|
||||||
if ( !PvNode
|
if ( !PvNode
|
||||||
&& ss->ttHit
|
&& ss->ttHit
|
||||||
&& tte->depth() >= ttDepth
|
&& tte->depth() >= ttDepth
|
||||||
|
@ -1464,7 +1466,7 @@ moves_loop: // When in check, search starts here
|
||||||
&& (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER)))
|
&& (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER)))
|
||||||
return ttValue;
|
return ttValue;
|
||||||
|
|
||||||
// Evaluate the position statically
|
// Step 4. Static evaluation of the position
|
||||||
if (ss->inCheck)
|
if (ss->inCheck)
|
||||||
{
|
{
|
||||||
ss->staticEval = VALUE_NONE;
|
ss->staticEval = VALUE_NONE;
|
||||||
|
@ -1522,7 +1524,8 @@ moves_loop: // When in check, search starts here
|
||||||
|
|
||||||
int quietCheckEvasions = 0;
|
int quietCheckEvasions = 0;
|
||||||
|
|
||||||
// Loop through the moves until no moves remain or a beta cutoff occurs
|
// Step 5. 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()) != MOVE_NONE)
|
||||||
{
|
{
|
||||||
assert(is_ok(move));
|
assert(is_ok(move));
|
||||||
|
@ -1536,9 +1539,11 @@ moves_loop: // When in check, search starts here
|
||||||
|
|
||||||
moveCount++;
|
moveCount++;
|
||||||
|
|
||||||
|
// Step 6. Pruning.
|
||||||
|
if (bestValue > VALUE_TB_LOSS_IN_MAX_PLY)
|
||||||
|
{
|
||||||
// Futility pruning and moveCount pruning (~10 Elo)
|
// Futility pruning and moveCount pruning (~10 Elo)
|
||||||
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
|
if ( !givesCheck
|
||||||
&& !givesCheck
|
|
||||||
&& to_sq(move) != prevSq
|
&& to_sq(move) != prevSq
|
||||||
&& futilityBase > -VALUE_KNOWN_WIN
|
&& futilityBase > -VALUE_KNOWN_WIN
|
||||||
&& type_of(move) != PROMOTION)
|
&& type_of(move) != PROMOTION)
|
||||||
|
@ -1561,43 +1566,43 @@ moves_loop: // When in check, search starts here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not search moves with bad enough SEE values (~5 Elo)
|
// We prune after 2nd quiet check evasion where being 'in check' is implicitly checked through the counter
|
||||||
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
|
// and being a 'quiet' apart from being a tt move is assumed after an increment because captures are pushed ahead.
|
||||||
&& !pos.see_ge(move, Value(-108)))
|
if (quietCheckEvasions > 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Continuation history based pruning (~3 Elo)
|
||||||
|
if ( !capture
|
||||||
|
&& (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < 0
|
||||||
|
&& (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Do not search moves with bad enough SEE values (~5 Elo)
|
||||||
|
if (!pos.see_ge(move, Value(-108)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Speculative prefetch as early as possible
|
// Speculative prefetch as early as possible
|
||||||
prefetch(TT.first_entry(pos.key_after(move)));
|
prefetch(TT.first_entry(pos.key_after(move)));
|
||||||
|
|
||||||
|
// Update the current move
|
||||||
ss->currentMove = move;
|
ss->currentMove = move;
|
||||||
ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
|
ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
|
||||||
[capture]
|
[capture]
|
||||||
[pos.moved_piece(move)]
|
[pos.moved_piece(move)]
|
||||||
[to_sq(move)];
|
[to_sq(move)];
|
||||||
|
|
||||||
// Continuation history based pruning (~3 Elo)
|
|
||||||
if ( !capture
|
|
||||||
&& bestValue > VALUE_TB_LOSS_IN_MAX_PLY
|
|
||||||
&& (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < 0
|
|
||||||
&& (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// We prune after 2nd quiet check evasion where being 'in check' is implicitly checked through the counter
|
|
||||||
// and being a 'quiet' apart from being a tt move is assumed after an increment because captures are pushed ahead.
|
|
||||||
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
|
|
||||||
&& quietCheckEvasions > 1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
quietCheckEvasions += !capture && ss->inCheck;
|
quietCheckEvasions += !capture && ss->inCheck;
|
||||||
|
|
||||||
// Make and search the move
|
// Step 7. Make and search the move
|
||||||
pos.do_move(move, st, givesCheck);
|
pos.do_move(move, st, givesCheck);
|
||||||
value = -qsearch<nodeType>(pos, ss+1, -beta, -alpha, depth - 1);
|
value = -qsearch<nodeType>(pos, ss+1, -beta, -alpha, depth - 1);
|
||||||
pos.undo_move(move);
|
pos.undo_move(move);
|
||||||
|
|
||||||
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
|
||||||
|
|
||||||
// Check for a new best move
|
// Step 8. Check for a new best move
|
||||||
if (value > bestValue)
|
if (value > bestValue)
|
||||||
{
|
{
|
||||||
bestValue = value;
|
bestValue = value;
|
||||||
|
@ -1617,6 +1622,7 @@ moves_loop: // When in check, search starts here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Step 9. Check for mate
|
||||||
// All legal moves have been searched. A special case: if we're in check
|
// All legal moves have been searched. A special case: if we're in check
|
||||||
// and no legal moves were found, it is checkmate.
|
// and no legal moves were found, it is checkmate.
|
||||||
if (ss->inCheck && bestValue == -VALUE_INFINITE)
|
if (ss->inCheck && bestValue == -VALUE_INFINITE)
|
||||||
|
|
Loading…
Add table
Reference in a new issue