moveCountPruning = singularQuietLMR = false;
// Indicate PvNodes that will probably fail low if the node was searched
- // at a depth equal to or greater than the current depth, and the result of this search was a fail low.
+ // at a depth equal to or greater than the current depth, and the result
+ // of this search was a fail low.
bool likelyFailLow = PvNode
&& ttMove
&& (tte->bound() & BOUND_UPPER)
// Singular extension search (~94 Elo). If all moves but one fail low on a
// search of (alpha-s, beta-s), and just one fails high on (alpha, beta),
// then that move is singular and should be extended. To verify this we do
- // a reduced search on all the other moves but the ttMove and if the
- // result is lower than ttValue minus a margin, then we will extend the ttMove.
- // Depth margin and singularBeta margin are known for having non-linear scaling.
- // Their values are optimized to time controls of 180+1.8 and longer
+ // a reduced search on all the other moves but the ttMove and if the result
+ // is lower than ttValue minus a margin, then we will extend the ttMove. Note
+ // that depth margin and singularBeta margin are known for having non-linear
+ // scaling. Their values are optimized to time controls of 180+1.8 and longer
// so changing them requires tests at this type of time controls.
if ( !rootNode
&& depth >= 4 - (thisThread->completedDepth > 22) + 2 * (PvNode && tte->is_pv())
}
// Multi-cut pruning
- // Our ttMove is assumed to fail high, and now we failed high also on a reduced
- // search without the ttMove. So we assume this expected Cut-node is not singular,
- // that multiple moves fail high, and we can prune the whole subtree by returning
- // a softbound.
+ // Our ttMove is assumed to fail high, and now we failed high also on a
+ // reduced search without the ttMove. So we assume this expected cut-node
+ // is not singular, that multiple moves fail high, and we can prune the
+ // whole subtree by returning a softbound.
else if (singularBeta >= beta)
return singularBeta;
// Step 16. Make the move
pos.do_move(move, st, givesCheck);
- // Decrease reduction if position is or has been on the PV
- // and node is not likely to fail low. (~3 Elo)
+ // Decrease reduction if position is or has been on the PV and not likely to fail low. (~3 Elo)
// Decrease further on cutNodes. (~1 Elo)
if ( ss->ttPv
&& !likelyFailLow)
if ((ss+1)->cutoffCnt > 3)
r++;
+ // Decrease reduction for first generated move (ttMove)
else if (move == ttMove)
r--;
futilityValue = futilityBase + PieceValue[pos.piece_on(to_sq(move))];
+ // If static eval + value of piece we are going to capture is much lower
+ // than alpha we can prune this move
if (futilityValue <= alpha)
{
bestValue = std::max(bestValue, futilityValue);
continue;
}
+ // If static eval is much lower than alpha and move is not winning material
+ // we can prune this move
if (futilityBase <= alpha && !pos.see_ge(move, VALUE_ZERO + 1))
{
bestValue = std::max(bestValue, futilityBase);
continue;
}
+
+ // If static exchange evaluation is much worse than what is needed to not
+ // fall below alpha we can prune this move
+ if (futilityBase > alpha && !pos.see_ge(move, (alpha - futilityBase) * 4))
+ {
+ bestValue = alpha;
+ continue;
+ }
}
// We prune after the second quiet check evasion move, where being 'in check' is