inline Value razor_margin(Depth d) { return Value(512 + 16 * int(d)); }
// Futility lookup tables (initialized at startup) and their access functions
- Value FutilityMargins[14][64]; // [depth][moveNumber]
int FutilityMoveCounts[2][32]; // [improving][depth]
- inline Value futility_margin(Depth d, int mn) {
- assert(DEPTH_ZERO <= d && d < 7 * ONE_PLY);
- return FutilityMargins[d][std::min(mn, 63)];
+ inline Value futility_margin(Depth d) {
+ return Value(100 * int(d));
}
// Reduction lookup tables (initialized at startup) and their access function
Reductions[0][0][hd][mc] += ONE_PLY / 2;
}
- // Init futility margins array
- for (d = 0; d < 14; ++d) for (mc = 0; mc < 64; ++mc)
- FutilityMargins[d][mc] = Value(112 * int(2.9 * log(d >= 1 ? double(d) : 1.0)) - 8 * mc + 45);
-
// Init futility move count array
for (d = 0; d < 32; ++d)
{
bestValue = -VALUE_INFINITE;
ss->currentMove = threatMove = (ss+1)->excludedMove = bestMove = MOVE_NONE;
ss->ply = (ss-1)->ply + 1;
- ss->futilityMoveCount = 0;
(ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
return v;
}
- // Step 7. post-Futility pruning (skipped when in check)
+ // Step 7. Futility pruning: child node (skipped when in check)
if ( !PvNode
&& !ss->skipNullMove
&& depth < 7 * ONE_PLY
- && eval - futility_margin(depth, (ss-1)->futilityMoveCount) >= beta
+ && eval - futility_margin(depth) >= beta
&& abs(beta) < VALUE_MATE_IN_MAX_PLY
&& abs(eval) < VALUE_KNOWN_WIN
&& pos.non_pawn_material(pos.side_to_move()))
- return eval - futility_margin(depth, (ss-1)->futilityMoveCount);
+ return eval - futility_margin(depth);
// Step 8. Null move search with verification search (is omitted in PV nodes)
if ( !PvNode
// Update current move (this must be done after singular extension search)
newDepth = depth - ONE_PLY + ext;
- Depth predictedDepth = newDepth - reduction<PvNode>(improving, depth, moveCount);
- // Step 13. Futility pruning (is omitted in PV nodes)
+ // Step 13. Pruning at shallow depth (exclude PV nodes)
if ( !PvNode
&& !captureOrPromotion
&& !inCheck
&& !dangerous
+ /* && move != ttMove Already implicit in the next condition */
&& bestValue > VALUE_MATED_IN_MAX_PLY)
{
// Move count based pruning
continue;
}
+ Depth predictedDepth = newDepth - reduction<PvNode>(improving, depth, moveCount);
+
+ // Futility pruning: parent node
+ if (predictedDepth < 7 * ONE_PLY)
+ {
+ Value futilityValue = ss->staticEval + futility_margin(predictedDepth) + Value(128);
+
+ if (futilityValue <= alpha)
+ {
+ bestValue = std::max(bestValue, futilityValue);
+
+ if (SpNode)
+ {
+ splitPoint->mutex.lock();
+ if (bestValue > splitPoint->bestValue)
+ splitPoint->bestValue = bestValue;
+ }
+ continue;
+ }
+ }
+
// Prune moves with negative SEE at low depths
if ( predictedDepth < 4 * ONE_PLY
&& pos.see_sign(move) < 0)
continue;
}
- // We have not pruned the move that will be searched, but remember how
- // far in the move list we are to be more aggressive in the child node.
- ss->futilityMoveCount = moveCount;
}
- else
- ss->futilityMoveCount = 0;
// Check for legality only before to do the move
if (!RootNode && !SpNode && !pos.legal(move, ci.pinned))