Skip to content

Mop-up: formulaic endgame king table converts won bare-king endings - #140

Open
thomasahle wants to merge 1 commit into
masterfrom
mopup-endgame
Open

Mop-up: formulaic endgame king table converts won bare-king endings#140
thomasahle wants to merge 1 commit into
masterfrom
mopup-endgame

Conversation

@thomasahle

Copy link
Copy Markdown
Owner

See commit message. Eight lines, formula-initialized (no stored table), activation-gated to bare-king positions so all normal play is bit-identical — the conversion battery is the metric: KRK 0/3 → 3/3 mates inside the 50-move budget, KQK 4–5× faster, stalemate1 and stalemate2 floors improve. Composes with the pending A1 fix (KPK) and leaves KBNK for corner-aware work if the TCEC field research says it matters.

🤖 Generated with Claude Code

With a bare king on the board the midgame king table gives the search
no progress signal: every shuffle scores alike, and won KRK endings
drift to the 50-move horizon (live examples in the loss audit: a K+R
vs K draw at halfmove 100; KQK mates at halfmove ~180).

Swap in a formula-initialized centralization gradient at the root of
each search whenever either side is down to a bare king: value falls
10cp per step of center manhattan distance. Both kings share the table
via rotation, so one swap simultaneously rewards driving the bare king
to the edge and marching our own king up - classical mop-up in 8 lines
and zero stored tables. Normal play is bit-identical (the swap only
engages with a bare king at the root); the table is fixed per search
and tp_score is cleared per search, so all bounds in a search target
one value function.

Conversion battery (depth 8, python-chess arbitration, 160-ply cap):
KRK a/b/c: 50-move draw -> MATE in 41/39/33 plies (inside the 50-move
budget); KQK a/b/c: mate in 77/59/41 -> 15/11/13 plies. KBNK remains
unconverted (needs corner-specific knowledge). Suite floors: all hold,
two improve - stalemate1 2/4 -> 3/4, stalemate2 10/130 -> 11/130 (floor
raised accordingly); mate1/2/3/4 unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thomasahle

Copy link
Copy Markdown
Owner Author

Can you explain more about how this solves KRK?

thomasahle added a commit that referenced this pull request Aug 6, 2026
…margin leak

Bounded (every static eval in [-MATE_UPPER, MATE_UPPER]) has been a
named hypothesis. This file proves the concrete fact from the real
tables (transcribed with the padding fold applied): for positions with
one king per side and <= 15 non-king pieces per side - true of every
reachable game - the eval is bounded by (kMax - kMin) + 15 * nkMax =
15437, strictly below MATE_LOWER = 50710. Stronger than Bounded needs:
static evals can never touch the mate band. The mop-up endgame table
(PR #140) is covered too.

Two subtleties surfaced and are machine-checked:
- The naive unconditional claim is FALSE: transiently kingless
  positions can exceed MATE_UPPER; the hypothesis is sound in use only
  because bound() short-circuits king-gone positions first. The
  one-king side condition records this.
- MATE_LOWER's margin leaks (kingGone_check_leaks): the max non-king
  army (9 promoted queens + 2R+2B+2N with PST bonuses) sums to 11749,
  exceeding the 10-queen margin 9290 by 2459 - so a kingless side
  facing a full army scores above -MATE_LOWER and the king-gone check
  misses it. Absurd position, real band leak. The repair
  MATE_LOWER = K - 13 * Q closes it (repaired_margin_covers) while
  every other consumer keeps its margin (evalBound_lt_repaired; king-
  capture move VALUES are ~59700, far above either constant). The
  constant change ships separately, measured per docs/TESTING.md.

The board-string-to-multiset link stays code-external (documented);
closing it against the real code is the lean-surfaces sf_pst track.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thomasahle added a commit that referenced this pull request Aug 6, 2026
…margin leak

Bounded (every static eval in [-MATE_UPPER, MATE_UPPER]) has been a
named hypothesis. This file proves the concrete fact from the real
tables (transcribed with the padding fold applied): for positions with
one king per side and <= 15 non-king pieces per side - true of every
reachable game - the eval is bounded by (kMax - kMin) + 15 * nkMax =
15437, strictly below MATE_LOWER = 50710. Stronger than Bounded needs:
static evals can never touch the mate band. The mop-up endgame table
(PR #140) is covered too.

Two subtleties surfaced and are machine-checked:
- The naive unconditional claim is FALSE: transiently kingless
  positions can exceed MATE_UPPER; the hypothesis is sound in use only
  because bound() short-circuits king-gone positions first. The
  one-king side condition records this.
- MATE_LOWER's margin leaks (kingGone_check_leaks): the max non-king
  army (9 promoted queens + 2R+2B+2N with PST bonuses) sums to 11749,
  exceeding the 10-queen margin 9290 by 2459 - so a kingless side
  facing a full army scores above -MATE_LOWER and the king-gone check
  misses it. Absurd position, real band leak. The repair
  MATE_LOWER = K - 13 * Q closes it (repaired_margin_covers) while
  every other consumer keeps its margin (evalBound_lt_repaired; king-
  capture move VALUES are ~59700, far above either constant). The
  constant change ships separately, measured per docs/TESTING.md.

The board-string-to-multiset link stays code-external (documented);
closing it against the real code is the lean-surfaces sf_pst track.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant