Repository navigation
Approximately +130 Elo over 1.6 (Ordo ~2930, Gauntlet 4 n=1040). Direct self-play vs 1.6: +139.1 Elo (n=10000) at 10+0.1.
Where 1.6 was an evaluation overhaul and 1.5 was one critical bug fix, 1.7 is split almost evenly between search and evaluation, and no single change dominates. The search gained a family of history tables, a static evaluation that is always available and cached in the transposition table, singular extensions, ProbCut, and a pawn-structure cache. The evaluation gained threat terms broken down by attacker and victim -- the largest single feature of the cycle -- plus endgame scaling that resolves a limitation carried since 1.5, and a re-fitted weight set.
Development was incremental and strict: every feature was added alone, measured in self-play against the previous accepted build, and kept only if it measured positive. Six were implemented in full and dropped. Two long checkpoint matches against 1.6 were run mid-cycle to keep the accumulated total honest, since summing individual gains overstates it.
Search -- move ordering
- Two-sided history heuristic: the butterfly history table now applies a penalty as well as a bonus. A quiet move that causes a cutoff is rewarded; every quiet move searched before it at the same node is penalized by the same amount. Both updates use a gravity form that decays entries toward a fixed asymptote instead of saturating them. About +15 Elo.
- Continuation history: a second history table conditioned on the opponent's previous move -- how good a move has been as a reply to that specific move, the generalization of the countermove heuristic. Combined one-to-one with the butterfly table. Persists across searches within a game. About +25 Elo.
Search -- evaluation channel and pruning
- Static evaluation always available, cached in the transposition table: every position outside check now has a static evaluation, taken from the transposition table when the position was seen before, computed otherwise, and refined by a usable stored score bound. Entries carry it at no size cost: the stored move was packed into its natural 16 bits, freeing exactly the two bytes needed, and entries remain exactly 16 bytes. About +20 Elo, and it made the next three items possible.
- Improving detection: with an evaluation at every node, the search can tell whether its position has been getting better since its previous move and modulate three pruning decisions accordingly -- in opposite directions, deliberately. Reverse futility prunes more when improving, move-level futility prunes less, and late move pruning tightens when not improving.
- Singular extensions: when the transposition table knows a node's best move to serious depth, the node re-searches itself with that move excluded against a window just below the stored score. If everything else falls short, that move is the only good one and is searched one ply deeper. About +5 Elo.
- ProbCut: at non-principal-variation nodes of sufficient depth, a shallow search of a sound capture that already beats beta by a solid margin cuts the node immediately. Slightly positive over 17,000 games; kept because it costs no speed and shrinks the tree markedly at depth.
Search -- speed
- Pawn structure cache: the pawn-structure part of the evaluation depends on nothing except where the pawns are. The board now maintains a second Zobrist key covering pawn placement alone, updated incrementally by the same code that maintains the main key, and the result is cached under it. Since pawn structure changes rarely during a search, most evaluations retrieve that work instead of repeating it. The cached values are identical to the computed ones by construction, so the benchmark signature is unchanged -- which is what proves the cache correct. About +20 Elo from the speed alone.
Evaluation
- Threat evaluation: what each side is attacking, broken down by attacker and victim rather than as one generic term -- pawns hitting minor pieces, pawns hitting rooks or queens, minor pieces hitting rooks or queens, rooks hitting the queen, enemy pieces attacked without being defended, and pawn advances that would create a threat from their new square. The attack maps this needs are the ones the mobility calculation already builds, so they are gathered there rather than recomputed, keeping the cost to about half a percent of search speed. About +50 Elo -- the single largest gain of the release, and measured before the new terms were fitted.
- Endgame recognition and scaling: the final evaluation is multiplied by a factor chosen from the material signature -- heavily reduced when the stronger side cannot force mate at all, moderately reduced for a rook against a single minor with no pawns, partly reduced for opposite-coloured bishops with a pawn difference of at most one. Combinations that genuinely win are untouched. The factor is never zero: an outright override to zero was tried in 1.5 and cost about 30 Elo, most likely because it erased the difference between keeping a piece and giving it away. About +8 Elo.
- Re-fitted weight set: all 946 evaluation weights re-optimized against a corpus of 7.15 million labelled positions after the threat terms were added with hand-chosen starting values. The correction concentrated where expected: the twelve threat weights moved about seven times more than the average of the rest, and moved coherently -- middlegame values up, endgame values down, matching what a threat is worth in each phase. About +6 Elo.
Robustness
- Hash option hardened, single-blend evaluation with a bit-exact trace, unlimited game history, maximum search ply raised to 256, and search depth clamped to the supported range. See the changelog for details; all measured neutral in self-play, as intended.
Features attempted and not shipped
- Capture history: roughly neutral over 16,250 games. The existing capture ordering was apparently already good enough that a learned refinement had nothing to add.
- History pruning: killed by instrumentation before any games were played. With efficient move ordering, genuinely bad quiet moves are rarely searched at all, so the penalty falls mostly on good-but-not-best moves; pruning on it made the tree grow rather than shrink.
- Principal variation search, two forms: both measured negative. Before the change every move at a principal-variation node produced an exact score for the transposition table; scouting replaces most of those with bounds, and the lost information costs more than the saved nodes return.
- Correction history: learning where the static evaluation is systematically wrong. Its expected range was ruled out early and it never separated from zero.
Known limitations resolved
- Drawn pawnless endings evaluated as material, carried from 1.5 and 1.6: resolved by the endgame scaling above. King and bishop against a lone king now evaluates near zero instead of near the value of a bishop.
Checksums (SHA1)
451890efd943e30113fd221f84eee0e229b98041 facon-1.7
0b39fa81e9326b4b172a61c71dccf12183940f01 facon-1.7.exe