Files
scrabble-solver/CLAUDE.md
T
Ilia Denisov 256999b42c Publish as versioned Gitea module; move dictionary pipeline out
- Rename module to gitea.iliadenisov.ru/developer/scrabble-solver so it can be
  consumed as a versioned dependency (no go.work replace / CI clone).
- De-internalize wordlist and dictdawg as public packages.
- Remove cmd/builddict, dictprep/, the dictionaries submodule and the dawg
  Makefile: the word-list parsing and DAWG build now live in the separate
  scrabble-dictionary repository, which publishes the DAWG set as a release artifact.
- internal/dict loads the committed dawg/en_sowpods.dawg fixture for cmd/stress.
- Update README/CLAUDE docs accordingly.
2026-06-04 19:11:46 +02:00

49 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# scrabble-solver — project guide
A Go library that, given a dictionary, a board position and a rack, returns every legal
play ranked by score, and scores/validates arbitrary plays. The move generator is the
**DAWG** algorithm (Appel & Jacobson) over `github.com/iliadenisov/dafsa` — a bit-packed,
minimised DAWG with a compact ≤63-symbol alphabet. A GADDAG generator was also built,
measured by self-play, and **removed**: DAWG won for this scoring-solver workload
(~7× smaller, comparable speed) — see `RESULTS.md`.
Module `scrabble-solver`, Go 1.26. Rulesets: English Scrabble, Russian Scrabble, and
Russian **Эрудит** (`rules` package); Эрудит has no Ё tile and folds Ё→Е in its dictionary.
## Layout
- `scrabble/` — the public API: `Solver` (`NewSolver`, `GenerateMoves`, `ScorePlay`,
`ValidatePlay`), the `Move`/`Placement`/`Word` types, the DAWG generator and scoring.
- `board/`, `rack/`, `rules/` — board grid (+ transpose), rack as per-letter counts,
and rulesets (geometry, premium layout, tile values/counts, alphabet, bonus):
`rules.English()`, `rules.RussianScrabble()`, `rules.Erudit()`.
- `dictdawg/`, `wordlist/`**public** helpers: `dictdawg` (build/load/serialise DAWGs
over dafsa), `wordlist` (encode/filter/sort/dedupe + `FoldYo`). Imported by the separate
`scrabble-dictionary` repo that builds and publishes the DAWG set.
- `internal/``encoding`, `graph`, `dict` (loads the committed `dawg/en_sowpods.dawg`
for `cmd/stress`).
- `cmd/stress`, `selfplay/` — the self-play stress harness behind `RESULTS.md`.
- `dawg/`**committed** dictionaries: `en_sowpods.dawg`, `ru_scrabble.dawg`,
`ru_erudit.dawg` (Ё→Е folded). The word-list sources and build pipeline live in the
separate [`scrabble-dictionary`](https://gitea.iliadenisov.ru/developer/scrabble-dictionary)
repo (which publishes the DAWG set as a release artifact); these committed copies are
test fixtures.
## Build & test
go test ./... # all packages green; also run go vet ./... and gofmt
Scoring and move generation are validated against **real tournament games** in GCG format
(`scrabble/gcg_test.go` + `scrabble/testdata/*.gcg`, including the 700+ club): for every
move the test checks the score, the running total, and that the generator actually
produces the played move with that score — canonical play, not invented cases.
## Key facts
- Compact byte encoding: low 6 bits = alphabet index; `0x80` = blank/wildcard (board, rack
and output bytes only — never inside the graph). The public API is byte-indexed.
- DAWG is the production generator; the GADDAG was removed after measurement.
- Detailed docs: `ALGORITHM.md` (the algorithm — single source of truth), `PLAN.md`
(design and decisions), `RESULTS.md` (DAWG-vs-GADDAG). The RU word-list pipeline and the
DAWG build now live in the `scrabble-dictionary` repo.