Tetrarch v4
v4 -- late move pruning. LMR searches the quiet tail shallower; this stops
searching it at all. Once 4 + depth² quiet moves have been tried without a
cutoff, at shallow depth and not in check, the rest are dropped. At a branching
factor near 60 that tail is most of the tree.
Elo | +36.09 +- 6.69 (95%)
SPRT | none -- sprt.py not built yet; fixed-N campaign
Conf | FIXED NODES 20000, Hash=256MB, classic/Teams, 100 workers
Games | N: 10000 (2500 openings x 4 rotations) score 5517.5 (55.18%)
Dist | 96, 6, 437, 36, 968, 33, 683, 16, 225
Null | -2.64 +- 6.24 on the same harness, 10000 games
Base | vs v3
Bench | 93,846,865 perft nodes (unchanged; the bench is perft, not search)
Pins | classic d5: 17,772 -> 7,449 search nodes (41.9%)
Screened +36.62 +- 15.43 over 2000 games and the confirm landed almost exactly
on the screen.
Search
- LMP --
LMPMaxDepth3,LMPBase4. Mean depth at the instrument goes
4.25 -> 5.25 over 40 positions, a full extra ply, and the depth 2-3 tail
disappears entirely. - The guard that matters is
legal >= 1. Without it a node could prune every
move, fall through with no legal moves, and report a checkmate that is not
there. Over 84 positions LMP missed a mate the full search finds 3 times and
invented one 0 times;selftestpins the never-invents property.
Cumulative
Four confirmed gains in, the search tree at classic depth 5 has gone from
228,628 nodes to 7,449 -- 3.3% of where v0 started -- and mean depth at 20,000
nodes from 3.73 to 5.25.
Tooling
match.pyno longer refuses to start when a--logor--pgn4name is
reused. It takes the next free name and prints it. A campaign log is the only
record of a run, so overwriting one silently stays unacceptable; refusing to
start over a name collision was friction with no safety value.