import { expect, test } from "bun:test"; import { DEPTHS, HEIGHT, WIDTH, at, distance, floorAt, openCells, seesFrom, stepToward, visibleFrom, walkable, xy, } from "./dungeon.ts"; test("a floor is the same floor every time it is asked for", () => { for (let depth = 1; depth <= DEPTHS; depth += 1) expect(floorAt(depth).tiles.join("")).toBe(floorAt(depth).tiles.join("")); expect(floorAt(1).tiles.join("")).not.toBe(floorAt(2).tiles.join("")); }); test("every floor has rooms, an entrance, and a way on", () => { for (let depth = 1; depth <= DEPTHS; depth += 1) { const floor = floorAt(depth); expect(floor.rooms.length).toBeGreaterThanOrEqual(5); expect(openCells(floor).length).toBeGreaterThan(150); expect(floor.tiles[floor.entrance]).toBe("<"); if (depth < DEPTHS) expect(floor.tiles[floor.descent as number]).toBe(">"); else expect(floor.descent).toBeUndefined(); } }); test("the stair is reachable from the entrance", () => { // A floor you cannot cross is a floor nobody can finish. Flood fill. for (let depth = 1; depth < DEPTHS; depth += 1) { const floor = floorAt(depth); const seen = new Set([floor.entrance]); const queue = [floor.entrance]; while (queue.length > 0) { const cell = queue.shift() as number; const { x, y } = xy(cell); for (const [dx, dy] of [[0,-1],[0,1],[1,0],[-1,0]] as const) { const nx = x + dx; const ny = y + dy; if (nx < 0 || ny < 0 || nx >= WIDTH || ny >= HEIGHT) continue; const next = at(nx, ny); if (seen.has(next) || !walkable(floor.tiles[next])) continue; seen.add(next); queue.push(next); } } expect(seen.has(floor.descent as number)).toBe(true); } }); test("a wall stops the light at the wall", () => { const floor = floorAt(1); const wall = floor.tiles.findIndex((t) => t === "#"); const lit = visibleFrom(floor, floor.entrance); expect(lit).toContain(floor.entrance); // Nothing lit is further than the lantern reaches. for (const cell of lit) expect(distance(floor.entrance, cell)).toBeLessThanOrEqual(4); // And sight into solid rock stops: a cell behind a wall is not visible. const blocked = floor.tiles.findIndex( (t, i) => t === "." && !seesFrom(floor, floor.entrance, i) && distance(floor.entrance, i) <= 4, ); if (blocked !== -1) expect(lit).not.toContain(blocked); expect(wall).toBeGreaterThan(-1); }); test("a step toward something goes around the corner it cannot go through", () => { const floor = floorAt(1); const from = floor.entrance; const step = stepToward(floor, from, floor.descent as number); expect(walkable(floor.tiles[step])).toBe(true); expect(distance(step, from)).toBeLessThanOrEqual(1); });