Skip to content

jumbled boards and big word graphs#95

Merged
andy-k merged 3 commits into
mainfrom
jumbled-boards-and-big-word-graphs
Jul 14, 2026
Merged

jumbled boards and big word graphs#95
andy-k merged 3 commits into
mainfrom
jumbled-boards-and-big-word-graphs

Conversation

@andy-k

@andy-k andy-k commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

this pr broadens the single-position endgame cli beyond classic spell-a-word configs to two previously unsupported axes: jumbled boards, where any anagram of the placed letters counts as a word, and word lists too large to index with 22 bits. jumbled configs are chosen with a jumbled- prefix (super- for the 21x21 board, combining as jumbled-super-) and use an alphagram dawg (.kad) rather than a gaddawg; the word-prune step that rebuilds only the still-playable words into a small graph for the solver used to hardcode a gaddawg, so on a jumbled config it produced a graph the movegen could not read. it now branches on game_rules() and builds the matching graph shape, factored into a build_pruned_kwg helper shared with the batch path. a -big suffix on the config name loads an oversized source graph as a 24-bit .kbwg while keeping the tiny pruned graph at 22 bits. the pr also carries an unrelated census fix so its progress line reports a reachable denominator, plus the endgame doc update.

Root cause

the census progress line "X of N leaves valued so far" used lat_len, the lattice's full combinatorial size (5379616 for English), as N. most of that lattice is unreachable: any subrack whose per-tile count exceeds that tile's bag frequency (e.g. 7 Q's) has no valid draw and can never be valued. a real 4x256 run had already converged at 4114349 valued after generation 1, but the inflated denominator made it look 27% incomplete.

Changes

  • endgame: word-prune now branches on game_rules(), building a gaddawg for classic and a dawg over make_alphagrams for jumbled, matching how the rest of movegen dispatches; extracted into a shared build_pruned_kwg helper.
  • endgame: config-name resolution handles the jumbled-, super-, and -big prefixes/suffix; -big loads the source graph as Node24 while the pruned graph stays Node22 since the surviving word set is always tiny.
  • census: progress denominator now uses the achievable count (4114349 for English), computed once at startup by unranking every lattice index and keeping those within base_freqs; value and accumulator arrays stay lat_len-sized.
  • docs: lab/endgame.txt updated for jumbled boards and big word graphs.

Correctness

the census fix touches only the progress eprintln! denominator, not any leave value or accumulator array. the endgame refactor keeps the classic batch path byte-identical (build_pruned_kwg builds a gaddawg there as before). the achievable ceiling was verified by an independent DP this session, with dp[7]=3199724 matching the known full-rack-drawable count. tests cover config-name resolution (jumbled/super/big) and that build_pruned_kwg emits the right shape per game_rules -- a word round-trips under its own config's lookup but not the other's.

andy-k added 3 commits July 12, 2026 05:41
The "X of N leaves valued so far" progress line used lat_len (the
lattice's full combinatorial size, 5379616 for English) as N. Most of
that lattice is unreachable: any subrack whose per-tile count exceeds
that tile's total bag frequency (e.g. 7 Q's) has no valid draw and can
never be valued. The true ceiling only counts subracks that pass the
same per-tile check the globally_possible closure already applies
per-rack elsewhere in this file (4114349 for English, verified by an
independent DP this session, dp[7]=3199724 matching the known
full-rack-drawable count). A real 4x256 run had already hit exactly
4114349 valued after generation 1 -- it had converged, but the old
denominator made it look 24% incomplete.

Fix computes the achievable count once at census startup (unrank every
lattice index, keep those within base_freqs) and uses it in place of
lat_len in the progress eprintln!. Does not touch any leave value or
the accumulator arrays, which stay lat_len-sized.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The single-position CLI only handled classic (spell-a-word) configs
loaded from a 22-bit .kwg. Two axes were missing:

- jumbled configs (any anagram of the letters counts as a word) need the
  config selected with a jumbled- prefix (super- for the 21x21 board,
  combining as jumbled-super-), and their word graph is an alphagram
  dawg (.kad), not a gaddawg. The word-prune step, which rebuilds only
  the words still playable on the board into a small graph for the
  solver, hardcoded a gaddawg -- so on a jumbled config it produced a
  graph the movegen could not read. It now branches on game_rules(): a
  gaddawg for classic, a dawg over make_alphagrams for jumbled, matching
  how the rest of movegen dispatches. Factored into a build_pruned_kwg
  helper shared with the batch path (classic, so byte-identical there).

- word lists too large for a 22-bit node index (e.g. Dutch) are built as
  a 24-bit .kbwg. A -big suffix on the config name (jumbled-dutch-big)
  loads the source graph as Node24 instead of Node22; the pruned graph
  stays Node22 since the surviving word set is always tiny.

Tests cover the config-name resolution (jumbled/super/big) and that
build_pruned_kwg emits the right shape per game_rules (a word round-
trips under its own config's lookup but not the other's).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@andy-k
andy-k merged commit 7165153 into main Jul 14, 2026
3 checks passed
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