Files
systemic-game-design-course/course/12-combat/reference/rust
Lucas WintherandClaude Opus 5.5 85959ba5a0
CI / Tool tests and sync-check (push) Successful in 16s
CI / Verify references (all modules, Rust and TS) (push) Successful in 2m4s
CI / Verify Expansion Drop solutions (all modules, Rust and TS) (push) Successful in 2m1s
CI / Coupling audit on references (push) Successful in 5s
CI / Differential fuzzing of the Rust and TS references (300 seeds) (push) Successful in 53s
CI / Mutation check (tools/mutants.json against the highest TS reference) (push) Successful in 34s
CI / Verify the SpellGrid level proofs (solver) (push) Successful in 5m25s
CI / Site build (push) Successful in 15s
CI / Naive engine tests (Module 0) (push) Successful in 20s
fix: final review (engine errors end a Sequence cleanly; nesting guard labelled as the course's; Node 22.15; minor lesson and tool fixes)
I1: run-scenario and both SpellGrid CLIs check moves first and treat any other engine
error as fatal (same text in both tracks); trigger blocks close on error (try/finally,
catch_unwind in Rust); unknown summons rejected. I2, I3, M1-M7, T3, T9a-c, T10a-b.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 14:58:27 +01:00
..

Module 12 reference engine (Rust)

The course's own engine as of the end of Module 12: Module 11's engine (Part I's card engine, Part II's grid engine with conditions, and SpellGrid joining them), with combat and the end of a turn in Part I. Every test from Modules 1–11 still passes. Module 11's reference was the starting point, so a diff between the two shows what this module adds. course/11-conditions/reference/rust/README.md and the READMEs it points to describe everything else.

  • cards/ and levels/ (at the crate root; not in this directory): staged by tools/verify-references.mjs as for Module 11, plus course/12-combat/cards/ (Test Bell).
  • Part I (src/engine/):
    • combat.rs (new): attack_error(world, attacker, defender), the legality rules (a minion in play attacks an enemy character in play, with more than 0 Attack, and a Taunt minion if the defender's side has one), and TAUNT.
    • card.rs: Card::keywords, compiled from keyword clauses. TriggerOn::EndOfTurn now fires.
    • event.rs: Event::TurnEnded { player }, which end of turn triggers answer. The course's log doesn't show it.
    • queue.rs: Action::Damage carries hits, each a target, an amount and a Priority (hits(targets, amount) builds the usual one-amount list). react takes the priority of each event's entries and sorts its Queue by priority, highest first, keeping the order it was filled in within one priority. Action::Attack builds one Damage action: the attacker's Attack to the defender at priority DEFENDER, and the defender's Attack (if more than 0) to the attacker at NORMAL. Action::EndTurn records TurnEnded and resolves the triggers that answer it.
  • src/harness.rs: order_attack(attacker, defender) -> Result<(), String>, can_attack(attacker, defender) -> Option<String> and end_turn(player) on Game.
  • Part II, Part III, src/cli.rs and src/bin/spellgrid.rs: unchanged from Module 11. SpellGrid doesn't attack. tools/diff-tracks.mjs uses this module's CLIs by default.

Run it with the module's tests: node tools/verify-references.mjs 12 from the course repository.