// Razor and futility margins
const int RazorMargin1 = 590;
const int RazorMargin2 = 604;
- Value futility_margin(Depth d) { return Value(150 * d / ONE_PLY); }
+ Value futility_margin(Depth d, bool improving) {
+ return Value((175 - 50 * improving) * d / ONE_PLY);
+ }
// Futility and reductions lookup tables, initialized at startup
int FutilityMoveCounts[2][16]; // [improving][depth]
alpha = std::max(rootMoves[PVIdx].previousScore - delta,-VALUE_INFINITE);
beta = std::min(rootMoves[PVIdx].previousScore + delta, VALUE_INFINITE);
- // Adjust contempt based on current bestValue
- ct = Options["Contempt"] * PawnValueEg / 100 // From centipawns
- + (bestValue > 500 ? 50: // Dynamic contempt
- bestValue < -500 ? -50:
- bestValue / 10);
+ ct = Options["Contempt"] * PawnValueEg / 100; // From centipawns
+
+ // Adjust contempt based on current bestValue (dynamic contempt)
+ ct += int(std::round(48 * atan(float(bestValue) / 128)));
Eval::Contempt = (us == WHITE ? make_score(ct, ct / 2)
: -make_score(ct, ct / 2));
if (inCheck)
{
ss->staticEval = eval = VALUE_NONE;
+ improving = true;
goto moves_loop;
}
else if (ttHit)
ss->staticEval, TT.generation());
}
+ improving = ss->staticEval >= (ss-2)->staticEval
+ ||(ss-2)->staticEval == VALUE_NONE;
+
if (skipEarlyPruning || !pos.non_pawn_material(pos.side_to_move()))
goto moves_loop;
// Step 7. Razoring (skipped when in check)
- if ( !PvNode
- && depth <= ONE_PLY)
+ if ( !PvNode
+ && depth <= 2 * ONE_PLY)
{
- if (eval + RazorMargin1 <= alpha)
+ if ( depth == ONE_PLY
+ && eval + RazorMargin1 <= alpha)
return qsearch<NonPV, false>(pos, ss, alpha, alpha+1);
- }
- else if ( !PvNode
- && depth <= 2 * ONE_PLY
- && eval + RazorMargin2 <= alpha)
- {
- Value ralpha = alpha - RazorMargin2;
- Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1);
- if (v <= ralpha)
- return v;
+
+ else if (eval + RazorMargin2 <= alpha)
+ {
+ Value ralpha = alpha - RazorMargin2;
+ Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1);
+
+ if (v <= ralpha)
+ return v;
+ }
}
// Step 8. Futility pruning: child node (skipped when in check)
if ( !rootNode
&& depth < 7 * ONE_PLY
- && eval - futility_margin(depth) >= beta
+ && eval - futility_margin(depth, improving) >= beta
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
return eval;
Value rbeta = std::min(beta + 200, VALUE_INFINITE);
MovePicker mp(pos, ttMove, rbeta - ss->staticEval, &thisThread->captureHistory);
+ int probCutCount = 0;
- while ((move = mp.next_move()) != MOVE_NONE)
+ while ( (move = mp.next_move()) != MOVE_NONE
+ && probCutCount < depth / ONE_PLY - 3)
if (pos.legal(move))
{
+ probCutCount++;
+
ss->currentMove = move;
ss->contHistory = thisThread->contHistory[pos.moved_piece(move)][to_sq(move)].get();
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, depth - 4 * ONE_PLY, !cutNode, false);
pos.undo_move(move);
+
if (value >= rbeta)
return value;
}
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory, contHist, countermove, ss->killers);
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
- improving = ss->staticEval >= (ss-2)->staticEval
- /* || ss->staticEval == VALUE_NONE Already implicit in the previous condition */
- ||(ss-2)->staticEval == VALUE_NONE;
singularExtensionNode = !rootNode
&& depth >= 8 * ONE_PLY