summaryrefslogtreecommitdiff
path: root/src/chess.h
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-10-13 11:12:35 -0700
committerScott Gasch <[email protected]>2026-10-13 11:12:35 -0700
commit7400001fc2d43a507b54281f9860c60177860fe5 (patch)
tree0ab8e3d1bd5fe54cc7f2883e38da67c3bfac36d8 /src/chess.h
parent78881b8e6422b7980e5f71780ae4bed862b93e72 (diff)
Add 5D FH% joint table (improve axis) + beta-side static-null-move
table, wire up static null-move pruning; misc searchsup.c tuning; --cpus=4 fix; multi-pool match_play.py openings. data.c: g_uJointFHThousandths grows a 5th "improve" axis ([12][11][11][15] -> [12][11][11][16][11]); new g_uBetaFHThousandths[12][21][11][11] table added. chess.h/searchsup.c/ search.c/split.c: minimal consumer wiring for the improve axis (ImproveBucket(), extended _JointTablePredictedFHThousandths signature/callers). search.c: new static (score-only, no verification search) null-move cutoff ahead of the existing real null-move check -- when iEval > iBeta by enough that the new beta-side table predicts a real null-move search would fail high with >95% confidence, take the cutoff on the table's say-so instead of paying for the verification search. searchsup.c: EstimateHangingMaterialCp now gives half credit when the mover has an unrelated piece already flagged trapped at node entry; bumped the SEE>=0 check extension from 3/4 ply to a full ply when the opponent has significant material left; removed the "entering the endgame extension" bonus (recapture extension and its window check untouched). main.c: accept "--opt=value" in addition to "--opt value" on the command line (a bare "--cpus=4" used to silently fail to match and leave uNumProcessors at its default of 1); also fixes a latent off-by-one that could read one past the end of argv for a value-taking flag given as the last command-line argument. unix.c: brace-scoping cleanup around signal handler setup, no behavior change. eval_tune/match_play.py, test_vs_head.sh: sample opening positions from multiple PGN pools (twic_filtered.pgn + lichess*.pgn) instead of one, for more opening diversity in match-play testing. Brought out of a larger stashed changeset one piece at a time, each verified independently against a --cpus 1 / --cpus 4 ratio benchmark to rule out the MP scaling regression that changeset originally triggered (see SCOTT_IS_A_MORON.md) -- no regression reproduced in any of the pieces here. Playing-strength impact measured as neutral via self-play (170 games, llr=-0.04, score=0.500) despite ~1 ply deeper average search. The stashed changeset's EFP margin rewrite, LMP threshold rewrite, and a disabled null-move-skip experiment are deliberately excluded -- those need their own careful, separate commits and testing. The stash's eval.c retuning is abandoned (measured ~even/worse over a ~700-game overnight self-play run). Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/chess.h')
-rwxr-xr-xsrc/chess.h51
1 files changed, 48 insertions, 3 deletions
diff --git a/src/chess.h b/src/chess.h
index 7e37245..91c6a0c 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -1007,6 +1007,24 @@ MOVE_STACK;
#define GAP_CP_BUCKET_WIDTH (100)
#define GAP_CP_BUCKETS (11)
+// 2026-10-10: "improving" axis -- does (iEval - iEval two plies ago,
+// same side to move) predict FH%? Signed and genuinely two-sided, so
+// a symmetric 100cp-wide-bin shape around a center "no real change"
+// bucket (index 5), with overflow buckets at both tails, matching
+// HANG/GAP's own 11-bucket count. Added as g_uJointFHThousandths's
+// 5th (trailing) axis -- see data.c.
+#define IMPROVE_BUCKET_WIDTH (100)
+#define IMPROVE_BUCKETS (11)
+#define IMPROVE_CP_CENTER_WIDTH (100) // center bucket covers (-100, 100)
+
+// 2026-10-10: gap-above-beta, for the beta-side static-NM table --
+// gated on iEval > iBeta, so always >= 0, no symmetric/center bucket
+// needed. Plain 100cp-wide bins from 0, wide enough (2000cp) to find
+// where FH% actually saturates toward ~100%, with an overflow bucket
+// past that.
+#define GAP_BETA_BUCKET_WIDTH (100)
+#define GAP_BETA_BUCKETS (21) // 0-99 .. 1900-1999, 20 == 2000cp+ overflow
+
// 2026-09-28: the "late axis" -- this move's own 1-based ordinal
// position in the list of moves actually tried at this node
// (uLegalMoves, right after MakeMove succeeds). Direct, unpaired
@@ -1094,7 +1112,8 @@ MOVE_STACK;
// COST of a wrong prune scales with remaining depth even where the rate
// does not.
// Shipped depth dimension of g_uJointFHThousandths (data.c declares it
-// as [12][11][11][15]; the 12 is _ShipDepthBucket's range).
+// as [12][11][11][16][11], including the 5th/improve axis; the 12 is
+// _ShipDepthBucket's range).
#define SHIP_DEPTH_BUCKETS (12)
#define PRUNE_VERIFY_BANDS (8)
// band edges, predicted FH in thousandths of a percent:
@@ -1330,6 +1349,13 @@ typedef struct _COUNTERS
#endif
UINT64 u64NullMoves;
UINT64 u64NullMoveSuccess;
+
+ // 2026-10-10: static (score-only, no verification search)
+ // null-move cutoff, gated on iEval > iBeta and the beta-side
+ // FH% table (g_uBetaFHThousandths) predicting a cutoff with
+ // >95% confidence -- see search.c's fTryBetaPruningHere block.
+ UINT64 u64QuickNullMoves;
+ UINT64 u64QuickNullMoveSuccess;
#ifdef TEST_NULL
// Precision/recall calibration for the null-move try/avoid
// decision. Indexed by _NullCalibBucketIndex() (search.c).
@@ -3299,7 +3325,13 @@ extern BITBOARD g_KingAttacksBB[128];
// depth outermost for cache locality -- a whole node's move loop shares
// one depth-slice (11*11*15 = 1,815 cells, ~3.5KB). Not yet consumed by
// search.c -- phase 2 (LMR replacement) is a separate, later step.
-extern USHORT g_uJointFHThousandths[12][11][11][15];
+extern USHORT g_uJointFHThousandths[12][11][11][16][11];
+
+// 2026-10-10: beta-side (static-null-move) 4D FH% table -- see data.c's
+// header. [depth][gapBeta][ownImprove][enemyImprove]. Cell stores the
+// GAP TO 100% FH rate (thousandths of a percentage point), not FH%
+// itself -- see _BetaTablePredictedFHThousandths's comment for why.
+extern USHORT g_uBetaFHThousandths[12][21][11][11];
// 2026-09-15: king-ring bitboard split for _EvalKing's linear-SCORE
// rewrite -- front/back mirror EmptyAttackedSquare's old color-dependent
@@ -3857,11 +3889,24 @@ MoveNumBucket(ULONG uMoveNum);
ULONG
DepthBucket(ULONG uCandDepth);
+ULONG
+ImproveBucket(SCORE iImprovement);
+
+ULONG
+GapBetaBucket(SCORE iGapBeta);
+
USHORT
_JointTablePredictedFHThousandths(IN ULONG uRawDepthBucket,
IN ULONG uRawDumbBucket,
IN ULONG uRawGapBucket,
- IN ULONG uRawLateBucket);
+ IN ULONG uRawLateBucket,
+ IN ULONG uRawImproveBucket);
+
+ULONG
+_BetaTablePredictedFHThousandths(IN ULONG uRawDepthBucket,
+ IN ULONG uGapBetaBucket,
+ IN ULONG uOwnImproveBucket,
+ IN ULONG uEnemyImproveBucket);
FLAG
WeShouldTryNullmovePruning(IN SEARCHER_THREAD_CONTEXT *ctx,