Add an optional "single word per turn" rule: only the main word along the
play direction is validated and scored; perpendicular cross-words are ignored
— not formed, validated, scored, or used to constrain move generation. The
zero PlayOptions stays standard Scrabble, so existing callers are unchanged.
- PlayOptions{IgnoreCrossWords} threaded through new EvaluateOpts,
Solver.{ScorePlay,ValidatePlay,GenerateMoves}Opts and the DAWG generator
(relaxed cross-sets via fullSet, main-word-only scoring).
- connected() tests perpendicular adjacency directly instead of via
Move.Cross, so an all-new main word touching the board only sideways still
connects when cross-words are suppressed (behaviour-preserving for standard
play).
- Tests: focused corner-case suite (solver_opts_test.go) and a single-word
GCG fixture; the 17 real-game GCG fixtures stay green as the standard-rules
regression guard.
- 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.
Replay 17 real tournament games (cross-tables.com, including the 700+ club) and
check, move for move, that:
- ScorePlay reproduces the protocol score and running total exactly;
- the move generator produces every dictionary-valid played move with that score.
The GCG parser handles coordinates (across/down), blanks (lowercase), played-through
tiles ("."), passes/exchanges, challenge bonuses, end-game rack adjustments and phony
withdrawals ("--", un-applied). Uses the committed dawg/en_sowpods.dawg.
Build a committed Russian common-noun word list (dictprep/russian/scrabble.txt)
from the RAN orthographic dictionary, for the Эрудит ruleset.
- Stage 1 (Go, dictprep/ruwords): orfo_dict_2025.txt -> all.txt; extracts
headwords, reconstructs "ед." singulars (suppressing plurals), pairs "и" variants.
- Stage 2 (Python brain, dictprep/ru_stage2.py): OpenCorpora (mawo-pymorphy3) +
libmorph + orthographic notes select common nouns (nom. sing.); --trace explains
a word's fate, --dump writes the in-memory buckets.
- libmorph C++ bridge (libmorph_check.cpp); manual_confirm.txt is merged in.
- orfo_dict_2025.txt is the committed pdftotext source of truth.
- See dictprep/README.md for methodology and reproducibility.
A Go library that returns every legal play ranked by score and scores or
validates plays, using the Appel-Jacobson DAWG algorithm over
github.com/iliadenisov/dafsa v1.1.0.
- DAWG move generation (across / down / both), full tournament scoring with a
per-tile breakdown; public Solver: GenerateMoves (ranked), ScorePlay,
ValidatePlay.
- Rulesets: English Scrabble, Russian Scrabble, Эрудит (parameterizable Ruleset).
- cmd/builddict (build the DAWG from the dictionaries submodule), cmd/stress
(self-play benchmark), selfplay engine; brute-force test oracle.
- A GADDAG was implemented, benchmarked and removed (the DAWG was smaller and
faster for a scoring solver); see RESULTS.md and ALGORITHM.md.