summaryrefslogtreecommitdiff
path: root/src/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval.c')
-rwxr-xr-xsrc/eval.c410
1 files changed, 345 insertions, 65 deletions
diff --git a/src/eval.c b/src/eval.c
index bc5f6f4..867c487 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -2820,6 +2820,43 @@ static UINT64 g_uMarginSwingSum[BASE_MARGIN_MAT_BUCKETS];
// moved"), this directly answers "was any real exit actually unsound".
static UINT64 g_uMarginExceeded[BASE_MARGIN_MAT_BUCKETS];
+// Same four counters, kept in a fully separate set for the super-lazy
+// exit (eval.c's material-only check before the regular lazy gate).
+// Its own SUPER_LAZY_MARGIN was never run through this harness when
+// it was added -- a much cheaper, much-larger-required-gap check than
+// the regular lazy exit, so mixing its swings into the buckets above
+// would wash out both regimes' signal.
+static UINT64 g_uSuperLazyMarginSwingMax[BASE_MARGIN_MAT_BUCKETS];
+static UINT64 g_uSuperLazyMarginSwingCount[BASE_MARGIN_MAT_BUCKETS];
+static UINT64 g_uSuperLazyMarginSwingSum[BASE_MARGIN_MAT_BUCKETS];
+static UINT64 g_uSuperLazyMarginExceeded[BASE_MARGIN_MAT_BUCKETS];
+
+static void
+_RecordMarginSafetySwingInto(IN OUT UINT64 *puMax,
+ IN OUT UINT64 *puCount,
+ IN OUT UINT64 *puSum,
+ IN OUT UINT64 *puExceeded,
+ IN POSITION *pos,
+ IN SCORE iSwing,
+ IN SCORE iActualMarginUsed)
+{
+ ULONG uMatBucket = _MaterialBucket(pos);
+
+ if (iSwing > iActualMarginUsed)
+ {
+ puExceeded[uMatBucket]++;
+ }
+
+ ASSERT(iSwing >= 0);
+ puCount[uMatBucket]++;
+ puSum[uMatBucket] += (UINT64)iSwing;
+ if ((UINT64)iSwing > puMax[uMatBucket])
+ {
+ puMax[uMatBucket] = (UINT64)iSwing;
+ }
+}
+
+
static void
RecordMarginSafetySwing(IN POSITION *pos,
IN SCORE iSwing,
@@ -2846,38 +2883,29 @@ Return value:
**/
{
- ULONG uMatBucket = _MaterialBucket(pos);
-
- if (iSwing > iActualMarginUsed)
- {
- g_uMarginExceeded[uMatBucket]++;
- }
-
- ASSERT(iSwing >= 0);
- g_uMarginSwingCount[uMatBucket]++;
- g_uMarginSwingSum[uMatBucket] += (UINT64)iSwing;
- if ((UINT64)iSwing > g_uMarginSwingMax[uMatBucket])
- {
- g_uMarginSwingMax[uMatBucket] = (UINT64)iSwing;
- }
+ _RecordMarginSafetySwingInto(g_uMarginSwingMax, g_uMarginSwingCount,
+ g_uMarginSwingSum, g_uMarginExceeded,
+ pos, iSwing, iActualMarginUsed);
}
-void
-DumpMarginSafetyCalibration(void)
+static void
+RecordSuperLazyMarginSafetySwing(IN POSITION *pos,
+ IN SCORE iSwing,
+ IN SCORE iActualMarginUsed)
/**
Routine description:
- Print, per material bucket, the max and average |real - lazy| swing
- observed among nodes that actually took a lazy exit this run
- (command.c's "calibrate marginsafety"). The max is the number that
- tells you how large LAZY_EVAL_BASE_MARGIN would need to be, at that
- material level, before an exit could have been unsound.
+ Same as RecordMarginSafetySwing, but for the super-lazy exit's own
+ separate bucket set -- see the comment on the g_uSuperLazyMargin*
+ arrays above for why these are kept apart.
Parameters:
- void
+ POSITION *pos
+ SCORE iSwing : >= 0
+ SCORE iActualMarginUsed : SUPER_LAZY_MARGIN
Return value:
@@ -2885,13 +2913,28 @@ Return value:
**/
{
+ _RecordMarginSafetySwingInto(g_uSuperLazyMarginSwingMax,
+ g_uSuperLazyMarginSwingCount,
+ g_uSuperLazyMarginSwingSum,
+ g_uSuperLazyMarginExceeded,
+ pos, iSwing, iActualMarginUsed);
+}
+
+
+static void
+_DumpMarginSafetyCalibrationInto(IN CHAR *szLabel,
+ IN UINT64 *puMax,
+ IN UINT64 *puCount,
+ IN UINT64 *puSum,
+ IN UINT64 *puExceeded)
+{
ULONG m;
- Trace("Margin safety -- max/avg |real - lazy| swing among exits taken, "
- "by material bucket:\n");
+ Trace("%s -- max/avg |real - lazy| swing among exits taken, "
+ "by material bucket:\n", szLabel);
for (m = 0; m < BASE_MARGIN_MAT_BUCKETS; m++)
{
- if (0 == g_uMarginSwingCount[m])
+ if (0 == puCount[m])
{
Trace(" material bucket %u (scaler %u-%u): no exits taken\n",
m, m * BASE_MARGIN_MAT_WIDTH,
@@ -2904,11 +2947,48 @@ Return value:
COMPILER_LONGLONG_UNSIGNED_FORMAT "\n",
m, m * BASE_MARGIN_MAT_WIDTH,
(m * BASE_MARGIN_MAT_WIDTH) + BASE_MARGIN_MAT_WIDTH - 1,
- g_uMarginSwingMax[m],
- (double)g_uMarginSwingSum[m] / (double)g_uMarginSwingCount[m],
- g_uMarginSwingCount[m], g_uMarginExceeded[m]);
+ puMax[m], (double)puSum[m] / (double)puCount[m],
+ puCount[m], puExceeded[m]);
}
}
+
+
+void
+DumpMarginSafetyCalibration(void)
+/**
+
+Routine description:
+
+ Print, per material bucket, the max and average |real - lazy| swing
+ observed among nodes that actually took a lazy exit this run
+ (command.c's "calibrate marginsafety") -- once for the regular lazy
+ exit (LAZY_EVAL_BASE_MARGIN / EstimatePositionalScore) and once for
+ the super-lazy exit (SUPER_LAZY_MARGIN), which is a different-enough
+ regime (cheaper check, much larger required gap) that lumping the
+ two together would hide whichever one is actually unsound. Either
+ section's max is the number that answers "how large would that
+ margin need to be, at that material level, before an exit there
+ could have been unsound."
+
+Parameters:
+
+ void
+
+Return value:
+
+ void
+
+**/
+{
+ _DumpMarginSafetyCalibrationInto("Regular lazy margin safety",
+ g_uMarginSwingMax, g_uMarginSwingCount,
+ g_uMarginSwingSum, g_uMarginExceeded);
+ _DumpMarginSafetyCalibrationInto("Super lazy margin safety",
+ g_uSuperLazyMarginSwingMax,
+ g_uSuperLazyMarginSwingCount,
+ g_uSuperLazyMarginSwingSum,
+ g_uSuperLazyMarginExceeded);
+}
#endif // CALIBRATE_MARGIN_SAFETY
@@ -3036,6 +3116,36 @@ Return value:
*piAlphaMargin += iKingTerm + iResidualP90;
*piBetaMargin += iKingTerm + iResidualP90;
+
+ // 2026-09-08: the p90 estimate above, while within its own
+ // documented "~10% wrong" design tolerance, still let the regular
+ // lazy exit's real swing exceed the margin actually used 2.11-
+ // 2.38% of the time at combined army scaler 16-31 (CALIBRATE_
+ // MARGIN_SAFETY, 1500 real-game positions, tests/twic_sample.ep_,
+ // sd 8) -- not because the swing itself is much bigger there (max
+ // observed 855/779, comparable to every other bucket's 603-701),
+ // but because REDUCED_MATERIAL_DOWN_SCALER shrinks the king term
+ // faster than the swing actually shrinks at that material level.
+ // Floor the combined margin at the measured max-per-bucket (with
+ // ~25% headroom) rather than re-deriving the whole p90 shape --
+ // this leaves the estimate above as the primary driver wherever
+ // it's already wide enough (buckets 4-7, where it already clears
+ // these floors) and only kicks in where it wasn't. Buckets 0-1
+ // never take a regular lazy exit at all (see LAZY_EVAL_MIN_
+ // MATERIAL) so were never measured; use bucket 2's floor there
+ // defensively rather than leaving them unfloored. Provisional --
+ // re-derive with `calibrate marginsafety` if this margin's shape
+ // changes again.
+ {
+ static const SCORE iSwingFloorByArmy[8] =
+ {
+ 1069, 1069, 1069, 974, 821, 876, 796, 754,
+ };
+ ULONG uMatBucket = MINU(
+ 7, (pos->uArmyScaler[WHITE] + pos->uArmyScaler[BLACK]) / 8);
+ *piAlphaMargin = MAX(*piAlphaMargin, iSwingFloorByArmy[uMatBucket]);
+ *piBetaMargin = MAX(*piBetaMargin, iSwingFloorByArmy[uMatBucket]);
+ }
}
@@ -5033,7 +5143,7 @@ SCORE
Eval(IN SEARCHER_THREAD_CONTEXT *ctx,
IN SCORE iAlpha,
IN SCORE iBeta,
- OUT SCORE *piPositional)
+ OUT SCORE (*piPositional)[2])
/**
Routine description:
@@ -5043,11 +5153,16 @@ Parameters:
SEARCHER_THREAD_CONTEXT *ctx,
SCORE iAlpha,
SCORE iBeta,
- SCORE *piPositional : if non-NULL, filled in with a magnitude
- (always >= 0) estimating the non-material component of the
- score -- exact if a full eval ran, a cheap estimate otherwise.
- Callers must treat it as an estimate either way; it's only
- ever used to size a pruning margin, never as a hard fact.
+ SCORE (*piPositional)[2] : if non-NULL, filled in with an estimate
+ of the non-material component of the score for each side,
+ indexed by absolute color (WHITE/BLACK) -- exact if a full
+ eval ran, a cheap estimate otherwise. On a lazy exit this is
+ always >= 0 (an optimistic margin); on a full eval it can be
+ negative (a side whose positional terms net worse than its
+ raw material), floored at -FUTILITY_BASE_MARGIN_FULL/2 so it can
+ only shrink a caller's margin so far. Callers must treat it
+ as an estimate either way; it's only ever used to size a
+ pruning margin, never as a hard fact.
Return value:
@@ -5061,8 +5176,8 @@ Return value:
PAWN_HASH_ENTRY *pHash;
COOR c;
ULONG u;
- ULONG uColor;
- ULONG xColor;
+ ULONG uColor = pos->uToMove;
+ ULONG xColor = FLIP(uColor);
BITBOARD bb;
FLAG fDeferred;
#ifdef EVAL_TIME
@@ -5079,6 +5194,12 @@ Return value:
FLAG fWouldHaveExited = FALSE;
SCORE iSavedLazyScore = 0;
SCORE iSavedLazyPositional = 0;
+ // Same idea, kept separate from the pair above: the super-lazy
+ // exit (added 2026-09-07) is a much cheaper, much-larger-gap check
+ // than the regular lazy exit and was never hooked into this
+ // harness -- see RecordSuperLazyMarginSafetySwing below.
+ FLAG fWouldHaveExitedSuperLazy = FALSE;
+ SCORE iSavedSuperLazyScore = 0;
#endif
ASSERT(IS_VALID_SCORE(iAlpha));
ASSERT(IS_VALID_SCORE(iBeta));
@@ -5086,17 +5207,140 @@ Return value:
ASSERT((pos->iMaterialBalance[WHITE] * -1) ==
pos->iMaterialBalance[BLACK]);
- pos->uNumTrapped[BLACK] = pos->uNumTrapped[WHITE] = 0;
-
- pos->iScore[BLACK] =
- (pos->uPawnMaterial[BLACK] + pos->uNonPawnMaterial[BLACK]);
- pos->iScore[WHITE] =
- (pos->uPawnMaterial[WHITE] + pos->uNonPawnMaterial[WHITE]);
+ pos->iScore[uColor] =
+ (pos->uPawnMaterial[uColor] + pos->uNonPawnMaterial[uColor]);
+ pos->iScore[xColor] =
+ (pos->uPawnMaterial[xColor] + pos->uNonPawnMaterial[xColor]);
#ifdef EVAL_DUMP
EvalTraceClear();
Trace("Material:\n%d\t\t%d\n", pos->iScore[WHITE], pos->iScore[BLACK]);
#endif
+ // Initialize army scalers here (moved ahead of the super-lazy exit
+ // point below, 2026-09-08 -- their only inputs, uNonPawnMaterial,
+ // are already available this early, and the super-lazy margin
+ // table needs a material bucket before it can run). We skip lazy
+ // eval if we're too late into an endgame.
+ pos->uArmyScaler[BLACK] = pos->uNonPawnMaterial[BLACK] - VALUE_KING;
+ pos->uArmyScaler[WHITE] = pos->uNonPawnMaterial[WHITE] - VALUE_KING;
+ pos->uArmyScaler[BLACK] /= VALUE_PAWN;
+ pos->uArmyScaler[WHITE] /= VALUE_PAWN;
+ ASSERT(!(pos->uArmyScaler[BLACK] & 0x80000000));
+ ASSERT(!(pos->uArmyScaler[WHITE] & 0x80000000));
+ pos->uArmyScaler[BLACK] = MINU(31, pos->uArmyScaler[BLACK]);
+ pos->uArmyScaler[WHITE] = MINU(31, pos->uArmyScaler[WHITE]);
+ ASSERT(pos->uArmyScaler[BLACK] >= 0);
+ ASSERT(pos->uArmyScaler[BLACK] <= 31);
+ ASSERT(pos->uArmyScaler[WHITE] >= 0);
+ ASSERT(pos->uArmyScaler[WHITE] <= 31);
+
+ // Super-lazy exit point.
+#ifdef LAZY_EVAL
+ // 2026-09-08: was a single flat 625 for every material level.
+ // CALIBRATE_MARGIN_SAFETY data (100 real-game positions, sd 8,
+ // tests/twic_sample.ep_) showed that's badly unsound at low
+ // material -- up to 9.3% of super-lazy exits in bare-king-plus-a-
+ // little-material positions (combined army scaler 0-7) had a real
+ // swing exceeding 625, max observed 1710 -- while richer positions
+ // (combined scaler 32+) never came close (max 893, well under
+ // 625... actually under 900, still comfortably bounded). Table
+ // indexed the same way _MaterialBucket buckets the calibration
+ // data (combined army scaler / 8, 8 buckets), so it can be
+ // re-derived directly from a "calibrate marginsafety" run. Values
+ // here are the observed max per bucket rounded up with headroom
+ // (~15-20%), not a hard theoretical bound -- provisional pending a
+ // larger/deeper calibration run; re-check before trusting this at
+ // sd well beyond 8.
+ static const SCORE SUPER_LAZY_MARGIN_BY_ARMY[8] =
+ {
+ 2000, 1800, 1800, 1750, 1000, 850, 850, 850,
+ };
+ ULONG uSuperLazyMatBucket = MINU(
+ 7, (pos->uArmyScaler[WHITE] + pos->uArmyScaler[BLACK]) / 8);
+ SCORE iSuperLazyMargin = SUPER_LAZY_MARGIN_BY_ARMY[uSuperLazyMatBucket];
+ {
+#ifdef EVAL_TIME
+ UINT64 uSuperLazyTimer = SystemReadTimeStampCounter();
+#endif
+ iScoreForSideToMove = (pos->iScore[uColor] -pos->iScore[xColor]);
+ ASSERT(IS_VALID_SCORE(iScoreForSideToMove));
+ if (iScoreForSideToMove + iSuperLazyMargin < iAlpha)
+ {
+ ASSERT(iScoreForSideToMove < iAlpha);
+ INC(ctx->sCounters.tree.u64SuperLazyEvals);
+ if (NULL != piPositional)
+ {
+ // No positional credit here -- a super-lazy verdict is
+ // already a confident material-only read that we're
+ // well outside the window; handing back extra slack
+ // just re-inflates the qsearch futility margin and
+ // defeats the point of taking the cheap exit. Let
+ // FUTILITY_BASE_MARGIN_BY_SOURCE[SUPERLAZY] alone
+ // govern from here.
+ (*piPositional)[WHITE] = 0;
+ (*piPositional)[BLACK] = 0;
+ ctx->uLastPositionalSource = EVAL_POSITIONAL_SOURCE_SUPERLAZY;
+ }
+#ifdef EVAL_TIME
+ ctx->sCounters.tree.u64CyclesEvalSuperLazy +=
+ (SystemReadTimeStampCounter() - uSuperLazyTimer);
+#endif
+#ifdef CALIBRATE_MARGIN_SAFETY
+ // Don't exit yet -- let the real full eval run below so we
+ // can measure the true swing against SUPER_LAZY_MARGIN,
+ // then restore this exact (zeroed) piPositional right
+ // before `end:` so the caller sees what a normal build
+ // would have returned.
+ fWouldHaveExitedSuperLazy = TRUE;
+ iSavedSuperLazyScore = iScoreForSideToMove;
+#else
+#ifdef EVAL_TIME
+ ctx->sCounters.tree.u64CyclesEvalPreLazy +=
+ (SystemReadTimeStampCounter() - uTimer);
+ ctx->sCounters.tree.u64CyclesSuperLazyExit +=
+ (SystemReadTimeStampCounter() - uTimer);
+ ctx->sCounters.tree.u64CyclesInEval +=
+ (SystemReadTimeStampCounter() - uTimer);
+#endif
+ goto end;
+#endif
+ }
+ if (iScoreForSideToMove - iSuperLazyMargin > iBeta)
+ {
+ ASSERT(iScoreForSideToMove > iBeta);
+ INC(ctx->sCounters.tree.u64SuperLazyEvals);
+ if (NULL != piPositional)
+ {
+ (*piPositional)[WHITE] = 0;
+ (*piPositional)[BLACK] = 0;
+ ctx->uLastPositionalSource = EVAL_POSITIONAL_SOURCE_SUPERLAZY;
+ }
+#ifdef EVAL_TIME
+ ctx->sCounters.tree.u64CyclesEvalSuperLazy +=
+ (SystemReadTimeStampCounter() - uSuperLazyTimer);
+#endif
+#ifdef CALIBRATE_MARGIN_SAFETY
+ fWouldHaveExitedSuperLazy = TRUE;
+ iSavedSuperLazyScore = iScoreForSideToMove;
+#else
+#ifdef EVAL_TIME
+ ctx->sCounters.tree.u64CyclesEvalPreLazy +=
+ (SystemReadTimeStampCounter() - uTimer);
+ ctx->sCounters.tree.u64CyclesSuperLazyExit +=
+ (SystemReadTimeStampCounter() - uTimer);
+ ctx->sCounters.tree.u64CyclesInEval +=
+ (SystemReadTimeStampCounter() - uTimer);
+#endif
+ goto end;
+#endif
+ }
+#ifdef EVAL_TIME
+ ctx->sCounters.tree.u64CyclesEvalSuperLazy +=
+ (SystemReadTimeStampCounter() - uSuperLazyTimer);
+#endif
+ }
+#endif
+
//
// Pawn eval. Note: if fDeferred comes back as TRUE then we have
// neither cleared nor initialized the attack tables. This is
@@ -5273,7 +5517,9 @@ Return value:
INC(ctx->sCounters.tree.u64LazyEvals);
if (NULL != piPositional)
{
- *piPositional = iAlphaMargin;
+ (*piPositional)[WHITE] = iAlphaMargin;
+ (*piPositional)[BLACK] = iAlphaMargin;
+ ctx->uLastPositionalSource = EVAL_POSITIONAL_SOURCE_LAZY;
}
#ifdef EVAL_TIME
ctx->sCounters.tree.u64CyclesEvalPreLazy +=
@@ -5300,7 +5546,9 @@ Return value:
INC(ctx->sCounters.tree.u64LazyEvals);
if (NULL != piPositional)
{
- *piPositional = iBetaMargin;
+ (*piPositional)[WHITE] = iBetaMargin;
+ (*piPositional)[BLACK] = iBetaMargin;
+ ctx->uLastPositionalSource = EVAL_POSITIONAL_SOURCE_LAZY;
}
#ifdef EVAL_TIME
ctx->sCounters.tree.u64CyclesEvalPreLazy +=
@@ -5375,20 +5623,7 @@ Return value:
//
// Pre-compute some common terms used in per-piece evals:
//
- // This is a scaler based on the size of the army for each side.
- //
- pos->uArmyScaler[BLACK] = pos->uNonPawnMaterial[BLACK] - VALUE_KING;
- pos->uArmyScaler[WHITE] = pos->uNonPawnMaterial[WHITE] - VALUE_KING;
- pos->uArmyScaler[BLACK] /= VALUE_PAWN;
- pos->uArmyScaler[WHITE] /= VALUE_PAWN;
- ASSERT(!(pos->uArmyScaler[BLACK] & 0x80000000));
- ASSERT(!(pos->uArmyScaler[WHITE] & 0x80000000));
- pos->uArmyScaler[BLACK] = MINU(31, pos->uArmyScaler[BLACK]);
- pos->uArmyScaler[WHITE] = MINU(31, pos->uArmyScaler[WHITE]);
- ASSERT(pos->uArmyScaler[BLACK] >= 0);
- ASSERT(pos->uArmyScaler[BLACK] <= 31);
- ASSERT(pos->uArmyScaler[WHITE] >= 0);
- ASSERT(pos->uArmyScaler[WHITE] <= 31);
+ pos->uNumTrapped[BLACK] = pos->uNumTrapped[WHITE] = 0;
pos->iReducedMaterialDownScaler[BLACK] =
pos->iReducedMaterialDownScaler[WHITE] = 0;
@@ -5695,18 +5930,61 @@ Return value:
(iScoreForSideToMove * (SCORE)uDrawDist / 16);
}
- //
- // Adjust dynamic positional component.
- //
- iAlphaMargin = abs(pos->iMaterialBalance[pos->uToMove] - iScoreForSideToMove);
+ // Adjust dynamic positional component. Unlike the lazy-exit
+ // margins above (always >= 0 by construction), this can go
+ // negative -- a side whose positional terms (king safety, pawn
+ // structure, hanging pieces, ...) net worse than its raw material
+ // gets a genuinely negative value here. search.c's futility
+ // margin (FUTILITY_BASE_MARGIN_BY_SOURCE[side's tier] +
+ // piPositional[side]) deliberately lets that shrink the margin --
+ // a positionally-bad side is less likely to be saved by an
+ // unexamined quiet move -- but floor it so one bad eval term
+ // can't collapse the margin arbitrarily far; this only ever runs
+ // on the full-eval exit, so -FUTILITY_BASE_MARGIN_FULL/2 (not the
+ // lazy/super-lazy tiers) caps the damage at half of that tier's
+ // base.
if (NULL != piPositional)
{
- *piPositional = iAlphaMargin;
+ (*piPositional)[WHITE] =
+ MAX(pos->iScore[WHITE] -
+ (SCORE)(pos->uPawnMaterial[WHITE] + pos->uNonPawnMaterial[WHITE]),
+ -(FUTILITY_BASE_MARGIN_FULL / 2));
+ (*piPositional)[BLACK] =
+ MAX(pos->iScore[BLACK] -
+ (SCORE)(pos->uPawnMaterial[BLACK] + pos->uNonPawnMaterial[BLACK]),
+ -(FUTILITY_BASE_MARGIN_FULL / 2));
+ ctx->uLastPositionalSource = EVAL_POSITIONAL_SOURCE_FULL;
}
g_Options.iLastEvalScore = iScoreForSideToMove;
#ifdef CALIBRATE_MARGIN_SAFETY
- if (TRUE == fWouldHaveExited)
+ if (TRUE == fWouldHaveExitedSuperLazy)
+ {
+ //
+ // Real (non-calibration) code checks super-lazy first and
+ // returns immediately on a hit -- so if this call would *also*
+ // have satisfied the regular lazy condition below, super-lazy
+ // is still what a normal build actually returns. Record/
+ // restore this one, not the regular-lazy save in the other
+ // branch.
+ //
+ RecordSuperLazyMarginSafetySwing(
+ pos, abs(iScoreForSideToMove - iSavedSuperLazyScore),
+ iSuperLazyMargin);
+ iScoreForSideToMove = iSavedSuperLazyScore;
+ if (NULL != piPositional)
+ {
+ (*piPositional)[WHITE] = 0;
+ (*piPositional)[BLACK] = 0;
+ // CALIBRATE_MARGIN_SAFETY builds: the FULL tag set above
+ // reflects the fallthrough that just ran for measurement
+ // purposes, not what a normal build actually returns here
+ // -- fix it back up to match the restored (super-lazy)
+ // values.
+ ctx->uLastPositionalSource = EVAL_POSITIONAL_SOURCE_SUPERLAZY;
+ }
+ }
+ else if (TRUE == fWouldHaveExited)
{
//
// The real swing: how far the true, full-eval score actually
@@ -5725,7 +6003,9 @@ Return value:
iScoreForSideToMove = iSavedLazyScore;
if (NULL != piPositional)
{
- *piPositional = iSavedLazyPositional;
+ (*piPositional)[WHITE] = iSavedLazyPositional;
+ (*piPositional)[BLACK] = iSavedLazyPositional;
+ ctx->uLastPositionalSource = EVAL_POSITIONAL_SOURCE_LAZY;
}
}
#endif