The rules of Grand Cross, and the word list they are checked against.
This exists as its own repository for one reason: the browser and the server have to run identical rules. The API verifies a score by replaying the player's move log through the same engine the browser played on, so a copy of these rules living in two places would eventually diverge, and verification would start rejecting honest games or scoring them differently.
| Package | Published | Purpose |
|---|---|---|
@grand-cross/engine |
yes | Board, pieces, moves, scoring, and simulate() |
@grand-cross/words |
yes | The ENABLE five letter word list as a compact module |
@grand-cross/tuning |
no | Offline lookahead bot and measurement harness |
Published packages go to public npm under the @grand-cross scope, matching how
@seamless-auth is scoped per product. The rules being public costs nothing: the
server verifies every score by replaying it, so knowing the scoring table does not
help anyone fake one.
The engine is pure. No Math.random, no Date, no I/O, no ambient state.
Every transition is a function of (state, move). That is what makes
simulate(seed, moves) reproducible, and reproducibility is the only reason the
server can trust a score it did not watch being earned.
If you are tempted to reach for the clock or a random number inside packages/engine,
that is the moment to stop and pass it in instead.
RULES_VERSION in packages/engine/src/version.ts identifies the rule set a game
was played under. Bump it for anything that changes how a move log plays out: the
piece distribution, the escalation curves, the scoring table, or move legality.
Runs are stored with the version they were played under, so a mismatch is detectable instead of silently rescoring old games. Rendering, wording and tooling changes are not rules changes.
Both grand-cross-ui and grand-cross-api install the published packages and
pin a version. They must be on the same major version of the engine, or submitted
runs will fail verification.
npm install
npm test
npm run buildThe tuning harness measures the game rather than the code:
npm run measure -- --games 40 --depth 3
npm run sweep -- --games 120Releases use Changesets, the same as the other published fells-code packages.
npm run changeset # describe the change and pick a bumpMerging to main runs the release workflow, which either opens a "Version
Packages" pull request or, once that is merged, publishes to npm. The engine and
word list are versioned together, so a rules change bumps both and consumers
cannot end up on a mismatched pair. Nothing is published from a developer machine.
See docs/releasing.md, including how to move from the bootstrap token to trusted publishing.