Files
systemic-game-design-course/course/01-handles/reference/ts/src/harness.ts
T
2026-10-29 00:17:31 +01:00

49 lines
1.7 KiB
TypeScript

// Test harness: the thin adapter the course tests call. It translates each
// call into engine operations and holds no rules of its own.
import { library } from "./content";
import { World, type Zone } from "./engine";
export type { Zone };
export type Id = number;
export type Player = 0 | 1;
export interface Game {
summon(card: string, player?: Player): Id; // to right end of board
addToHand(card: string, player?: Player): Id;
addToDeck(card: string, player?: Player): Id;
play(handId: Id): void; // Expansion Drop
zoneOf(id: Id): Zone;
board(player: Player): Id[]; // left to right
hand(player: Player): Id[];
orderOfPlay(id: Id): number;
nameOf(id: Id): string;
}
export function newGame(opts?: { decks?: [string[], string[]] }): Game {
const world = new World(library());
opts?.decks?.forEach((deck, player) => {
for (const card of deck) world.create(card, player as Player, "deck");
});
return {
summon: (card, player = 0) => world.create(card, player, "board"),
addToHand: (card, player = 0) => world.create(card, player, "hand"),
addToDeck: (card, player = 0) => world.create(card, player, "deck"),
// Module 1 Expansion Drop: see course/01-handles/expansion/README.md.
play: () => {
throw new Error("not implemented: Module 1 Expansion Drop");
},
zoneOf: (id) => world.zoneOf(id),
board: (player) => [...world.zone(player, "board")],
hand: (player) => [...world.zone(player, "hand")],
orderOfPlay: (id) => {
const order = world.orderOfPlay(id);
if (order === undefined) throw new Error(`entity ${id} has not entered play`);
return order;
},
nameOf: (id) => world.cardName(id),
};
}