Stage 2: engine package over scrabble-solver (registry, bag, Game, replay)
backend/internal/engine wraps the sibling scrabble-solver library in-process: - Registry: versioned DAWG load via dafsa.Load, keyed by (variant, dict_version), latest-per-variant; English / Russian / Эрудит handled uniformly. - Bag: own deterministic, seeded tile bag with Draw + Return (for exchanges), since the solver's self-play bag cannot return tiles. - Game: pure rules engine — deal, play/pass/exchange/resign, refill, per-move scoring, turn order, and end-condition detection (empty bag + empty rack, six scoreless turns, resignation) with end-game rack adjustment. - decode/ReplayBoard: dictionary-independent MoveRecords and board replay via scrabble.Apply (no internal/encoding), realising ARCHITECTURE §9.1. Wiring: go.work gains "replace scrabble-solver => ../scrabble-solver"; backend requires scrabble-solver (placeholder) and github.com/iliadenisov/dafsa directly. Both Go CI workflows clone the public solver sibling (master HEAD, no token) and set BACKEND_DICT_DIR. Docs: ARCHITECTURE §5/§14, TESTING engine layer, backend README, and PLAN refinements + deferred TODOs (publish/version solver; split engine vs dictionary generator).
This commit is contained in:
+26
-1
@@ -12,6 +12,12 @@ and the durable accounts / identities / sessions data model. The session and
|
||||
account REST endpoints are added with the `gateway` (Stage 6); Stage 1 ships the
|
||||
store/service layer they will call.
|
||||
|
||||
Stage 2 adds `internal/engine`, the in-process bridge to the `scrabble-solver`
|
||||
library: a versioned dictionary registry, a deterministic tile bag, and a pure
|
||||
rules `Game` (legal plays, passes, exchanges, resignations and end-condition
|
||||
detection) that emits dictionary-independent move records. It is a library only;
|
||||
the game domain wires it into the server in Stage 3.
|
||||
|
||||
## Package layout
|
||||
|
||||
```
|
||||
@@ -25,6 +31,7 @@ internal/postgres/ # pgx-over-database/sql pool (otelsql), goose migrations
|
||||
internal/account/ # durable accounts + platform/email identities (store)
|
||||
internal/session/ # opaque tokens, sessions store, write-through cache, service
|
||||
internal/server/ # gin engine, route groups, X-User-ID middleware, probes
|
||||
internal/engine/ # in-process scrabble-solver bridge: registry, bag, Game, replay
|
||||
```
|
||||
|
||||
## Configuration (environment)
|
||||
@@ -64,6 +71,22 @@ regenerate the committed go-jet code (needs Docker):
|
||||
go run ./cmd/jetgen # rewrites internal/postgres/jet against a temp container
|
||||
```
|
||||
|
||||
## Engine & dictionaries
|
||||
|
||||
`internal/engine` consumes the sibling `scrabble-solver` module in-process. Its
|
||||
bare module path (`scrabble-solver`, not a URL) cannot be fetched via VCS, so the
|
||||
workspace `go.work` carries `replace scrabble-solver => ../scrabble-solver` and
|
||||
the build must run from the repository root (the workspace), not from this module
|
||||
in isolation. `github.com/iliadenisov/dafsa` (the DAWG loader) is a direct
|
||||
dependency. CI clones the public solver repository into `../scrabble-solver`
|
||||
before building (see `.gitea/workflows/`); locally, check it out next to this
|
||||
repository. Committed dictionaries (`en_sowpods.dawg`, `ru_scrabble.dawg`,
|
||||
`ru_erudit.dawg`) live in the solver's `dawg/` directory; the engine loads them
|
||||
by `(variant, dict_version)` from a directory path. A configurable
|
||||
`BACKEND_DICT_DIR` is wired when the first consumer needs it (Stage 3); the
|
||||
future versioned-artifact direction is recorded in [`../PLAN.md`](../PLAN.md)
|
||||
TODO-2.
|
||||
|
||||
## Tests
|
||||
|
||||
```sh
|
||||
@@ -73,4 +96,6 @@ go test -tags=integration -count=1 -p=1 ./... # Postgres-backed (needs Docker)
|
||||
|
||||
Integration tests are guarded by the `integration` build tag and run against a
|
||||
throwaway `postgres:17-alpine` container; they fail loudly when Docker is absent
|
||||
rather than skipping.
|
||||
rather than skipping. The `internal/engine` tests load the committed DAWGs from
|
||||
`BACKEND_DICT_DIR` (defaulting to the sibling `../scrabble-solver/dawg`) and fail
|
||||
loudly when that directory is absent.
|
||||
|
||||
Reference in New Issue
Block a user