- SpellGrid cards move to course/10-spellgrid/cards; start-module and verify-references stage course/cards plus module-local cards up to the module, so M5-M9 workspaces get exactly the pre-M10 card set. - cast() rejects a chosen-target spell without a target (checkCast/checkPlay); new test_10_targeted_spell_needs_target. - Rust CLI pre-validates instead of swapping the global panic hook. - Catalog: CRIER noun; DEATHRATTLE/BATTLECRY note on lexicon vs catalog role. - Lesson: design note on mid-movement reparse. Co-Authored-By: Claude Opus 5.5 <[email protected]>
21 lines
2.9 KiB
Markdown
21 lines
2.9 KiB
Markdown
# Module 10 reference engine (Rust)
|
||
|
||
The course's own engine as of the end of Module 10: Part I's card engine and Part II's grid engine, joined by SpellGrid. Every test from Modules 1–9 still passes. Module 9's reference was the starting point, so a diff between the two shows what this module adds.
|
||
|
||
- `cards/` and `levels/` (at the crate root; not in this directory): copies of `course/cards/` plus `course/10-spellgrid/cards/` (SpellGrid's own cards, which only Module 10 on receives), and of `course/10-spellgrid/levels/`, staged by `tools/verify-references.mjs`.
|
||
- `src/engine/spellgrid.rs` (new): the only module that uses both engines. `SpellGrid` keeps a `World` and a `puzzle::Level` in step through the three seams: `rule_auras` (rules in force → auras), `CardSide::destroy` (hazard victims → one `Destroy` Sequence → the Death Creation Step), and `CardSide::sequence` (after each Sequence: write `TextSpawned` text, take dead minions off the grid, reparse). It also keeps one id space: a minion's id is its grid object's id.
|
||
- Part I (`src/engine/`, outside `puzzle/`):
|
||
- `queue.rs`: `END_OF_PHASE` (`[DeathCreation, AuraUpdate]`) is the list of steps at the end of the outermost Phase, read from the world. `Action::SpawnText` records a `TextSpawned` event.
|
||
- `world.rs`: `set_rule_auras`/`rule_auras` (auras that no minion carries), `set_end_of_phase`/`end_of_phase`, `entity_count`.
|
||
- `aura.rs`: an Aura Update adds the rule auras for both players; `activations` applies an `Aura::TriggerCap`.
|
||
- `card.rs`: `Aura::TriggerCap` (not in the card format: only SpellGrid makes it), and `CardDef::noun`.
|
||
- `effect.rs`: `spawnText` is an action, not a panic. `event.rs`: `TextSpawned`.
|
||
- Part II (`src/engine/puzzle/`):
|
||
- `level.rs`: `Destroy` and `remove_all`. `step_with` and `move_you_with` take a destroy function, which movement, conversion (`X IS NOT X`) and hazards hand their victims to; `step` and `move_you` pass `remove_all`. `reparse` and `board_mut` are public.
|
||
- `grid.rs`: `Board::reserve_id`, and `cards`/`hand` in `LevelDef` (read only by SpellGrid), with `LevelCard`.
|
||
- `src/content/seams.json` and `seams()` (new): which nouns name a trigger (`DEATHRATTLE`) and which properties multiply one (`DOUBLE`, twice, `stacking: "max"`). `words.json` adds the SpellGrid nouns, `DEATHRATTLE` and `DOUBLE`.
|
||
- `src/harness.rs`: Module 10 adds `new_spell_grid` and `SpellGrid`, including the test hook `with_naive_aura_timing()`, which reverses `END_OF_PHASE` for one game.
|
||
- `src/cli.rs` and `src/bin/spellgrid.rs` (new): the command line, `cargo run --bin spellgrid -- levels/l1-double-tap.json` from a staged workspace (it needs `cards/` and `levels/`). `w a s d` move, `c <card> [x y]` casts a spell (at the minion on that tile) or plays a minion (onto that empty tile), `q` quits. `tests/cli.rs` plays it from a script; it is the reference's own check, not a course test.
|
||
|
||
Run it with the module's tests: `node tools/verify-references.mjs 10` from the course repository.
|