// Module 8: Push chains. Each test matches a heading in scenarios.md. import { expect, test } from "vitest"; import { newBaba, type Baba } from "../src/harness"; /** An empty level `width` wide and `height` high. */ const emptyLevel = (width: number, height: number) => ({ width, height, objects: [] }); /** Place one text object per word: `[word, x, y]`. */ function write(b: Baba, words: [string, number, number][]): void { for (const [word, x, y] of words) b.place(`text:${word}`, x, y); } test("test_08_chain_moves_together", () => { const b = newBaba(emptyLevel(6, 4)); write(b, [ ["BABA", 0, 0], ["IS", 1, 0], ["YOU", 2, 0], ]); write(b, [ ["ROCK", 0, 1], ["IS", 1, 1], ["PUSH", 2, 1], ]); const baba = b.place("baba", 0, 3); const rocks = [b.place("rock", 1, 3), b.place("rock", 2, 3), b.place("rock", 3, 3)]; b.move("right"); expect(b.posOf(baba)).toEqual([1, 3]); expect(b.posOf(rocks[0])).toEqual([2, 3]); expect(b.posOf(rocks[1])).toEqual([3, 3]); expect(b.posOf(rocks[2])).toEqual([4, 3]); expect(b.kindsAt(0, 3)).toEqual([]); expect(b.kindsAt(4, 3)).toEqual(["rock"]); }); test("test_08_chain_into_stop_nothing_moves", () => { const b = newBaba(emptyLevel(6, 5)); write(b, [ ["BABA", 0, 0], ["IS", 1, 0], ["YOU", 2, 0], ]); write(b, [ ["ROCK", 0, 1], ["IS", 1, 1], ["PUSH", 2, 1], ]); write(b, [ ["WALL", 0, 2], ["IS", 1, 2], ["STOP", 2, 2], ]); const baba = b.place("baba", 0, 4); const rocks = [b.place("rock", 1, 4), b.place("rock", 2, 4), b.place("rock", 3, 4)]; const wall = b.place("wall", 4, 4); b.move("right"); expect(b.posOf(baba)).toEqual([0, 4]); expect(b.posOf(rocks[0])).toEqual([1, 4]); expect(b.posOf(rocks[1])).toEqual([2, 4]); expect(b.posOf(rocks[2])).toEqual([3, 4]); expect(b.posOf(wall)).toEqual([4, 4]); }); test("test_08_open_shut_during_push", () => { const b = newBaba(emptyLevel(5, 5)); write(b, [ ["BABA", 0, 0], ["IS", 1, 0], ["YOU", 2, 0], ]); write(b, [ ["KEY", 0, 1], ["IS", 1, 1], ["PUSH", 2, 1], ["AND", 3, 1], ["OPEN", 4, 1], ]); write(b, [ ["DOOR", 0, 2], ["IS", 1, 2], ["STOP", 2, 2], ["AND", 3, 2], ["SHUT", 4, 2], ]); const baba = b.place("baba", 0, 4); const key = b.place("key", 1, 4); const door = b.place("door", 2, 4); b.move("right"); expect(b.posOf(key)).toBeNull(); expect(b.posOf(door)).toBeNull(); // Inferred, not stated by a source: Baba lands on the key's former tile. expect(b.posOf(baba)).toEqual([1, 4]); expect(b.kindsAt(2, 4)).toEqual([]); expect(b.kindsAt(1, 4)).toEqual(["baba"]); }); test("test_08_text_pushed", () => { const b = newBaba(emptyLevel(4, 5)); write(b, [ ["BABA", 0, 0], ["IS", 1, 0], ["YOU", 2, 0], ]); const baba = b.place("baba", 0, 2); const rockText = b.place("text:ROCK", 1, 2); write(b, [ ["IS", 2, 3], ["PUSH", 2, 4], ]); expect(b.rules()).toEqual(["BABA IS YOU", "TEXT IS PUSH"]); b.move("right"); expect(b.posOf(baba)).toEqual([1, 2]); expect(b.posOf(rockText)).toEqual([2, 2]); expect(b.rules()).toEqual(["BABA IS YOU", "ROCK IS PUSH", "TEXT IS PUSH"]); }); test("test_08_level_edge_is_stop", () => { const b = newBaba(emptyLevel(3, 3)); write(b, [ ["BABA", 0, 0], ["IS", 1, 0], ["YOU", 2, 0], ]); const baba = b.place("baba", 1, 2); const flagText = b.place("text:FLAG", 2, 2); b.move("right"); expect(b.posOf(baba)).toEqual([1, 2]); expect(b.posOf(flagText)).toEqual([2, 2]); b.move("down"); expect(b.posOf(baba)).toEqual([1, 2]); expect(b.posOf(flagText)).toEqual([2, 2]); });