Files
systemic-game-design-course/course/12-combat/reference/ts
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 (TypeScript)

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/ts/README.md and the READMEs it points to describe everything else.

  • cards/ and levels/ (at the package 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.ts (new): attackError(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.ts: Card.keywords, compiled from keyword clauses. "endOfTurn" now fires.
    • event.ts: { type: "TurnEnded", player }, which end of turn triggers answer. The course's log doesn't show it.
    • queue.ts: the damage action 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. The attack action 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. The endTurn action records TurnEnded and resolves the triggers that answer it.
  • src/harness.ts: orderAttack(attacker, defender) (throws an Error with the reason if the attack is illegal), canAttack(attacker, defender): string | null and endTurn(player) on Game.
  • Part II, Part III and src/cli.ts: 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.