1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-02 01:29:36 +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:
Michael Chaly 2023-02-04 23:46:44 +03:00 committed by Joost VandeVondele
parent d5817a5896
commit 8f843633db

View file

@ -1427,6 +1427,7 @@ moves_loop: // When in check, search starts here
bool pvHit, givesCheck, capture;
int moveCount;
// Step 1. Initialize node
if (PvNode)
{
(ss+1)->pv = pv;
@ -1438,7 +1439,7 @@ moves_loop: // When in check, search starts here
ss->inCheck = pos.checkers();
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)
|| ss->ply >= MAX_PLY)
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.
ttDepth = ss->inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
: DEPTH_QS_NO_CHECKS;
// Transposition table lookup
// Step 3. Transposition table lookup
posKey = pos.key();
tte = TT.probe(posKey, ss->ttHit);
ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE;
ttMove = ss->ttHit ? tte->move() : MOVE_NONE;
pvHit = ss->ttHit && tte->is_pv();
// At non-PV nodes we check for an early TT cutoff
if ( !PvNode
&& ss->ttHit
&& tte->depth() >= ttDepth
@ -1464,7 +1466,7 @@ moves_loop: // When in check, search starts here
&& (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER)))
return ttValue;
// Evaluate the position statically
// Step 4. Static evaluation of the position
if (ss->inCheck)
{
ss->staticEval = VALUE_NONE;
@ -1522,7 +1524,8 @@ moves_loop: // When in check, search starts here
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)
{
assert(is_ok(move));
@ -1536,9 +1539,11 @@ moves_loop: // When in check, search starts here
moveCount++;
// Step 6. Pruning.
if (bestValue > VALUE_TB_LOSS_IN_MAX_PLY)
{
// Futility pruning and moveCount pruning (~10 Elo)
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !givesCheck
if ( !givesCheck
&& to_sq(move) != prevSq
&& futilityBase > -VALUE_KNOWN_WIN
&& 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)
if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY
&& !pos.see_ge(move, Value(-108)))
// 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 (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;
// 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
prefetch(TT.first_entry(pos.key_after(move)));
// Update the current move
ss->currentMove = move;
ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck]
[capture]
[pos.moved_piece(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;
// Make and search the move
// Step 7. Make and search the move
pos.do_move(move, st, givesCheck);
value = -qsearch<nodeType>(pos, ss+1, -beta, -alpha, depth - 1);
pos.undo_move(move);
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
// Check for a new best move
// Step 8. Check for a new best move
if (value > bestValue)
{
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
// and no legal moves were found, it is checkmate.
if (ss->inCheck && bestValue == -VALUE_INFINITE)