Feature: implement dungeon state management with room expansion and exit handling

This commit is contained in:
Keith Solomon
2026-03-15 13:05:48 -05:00
parent 120e144b3f
commit 1ff20723ec
3 changed files with 300 additions and 2 deletions

87
src/rules/dungeon.test.ts Normal file
View File

@@ -0,0 +1,87 @@
import { describe, expect, it } from "vitest";
import { sampleContentPack } from "@/data/sampleContentPack";
import {
expandLevelFromExit,
getUnresolvedExits,
initializeDungeonLevel,
} from "./dungeon";
function createSequenceRoller(values: number[]) {
let index = 0;
return () => {
const next = values[index];
index += 1;
return next;
};
}
describe("dungeon state", () => {
it("initializes level 1 with a generated start room", () => {
const levelState = initializeDungeonLevel({ content: sampleContentPack });
expect(levelState.level).toBe(1);
expect(levelState.discoveredRoomOrder).toEqual(["room.level1.start"]);
expect(levelState.rooms["room.level1.start"]?.roomClass).toBe("start");
});
it("lists unresolved traversable exits in discovery order", () => {
const levelState = initializeDungeonLevel({ content: sampleContentPack });
expect(getUnresolvedExits(levelState)).toEqual([
expect.objectContaining({
roomId: "room.level1.start",
direction: "north",
}),
]);
});
it("expands the dungeon from a chosen exit and links both rooms", () => {
const levelState = initializeDungeonLevel({ content: sampleContentPack });
const result = expandLevelFromExit({
content: sampleContentPack,
levelState,
fromRoomId: "room.level1.start",
exitDirection: "north",
roomTableCode: "L1SR",
roller: createSequenceRoller([3, 3]),
});
expect(result.createdRoom.position).toEqual({ x: 0, y: -1 });
expect(result.levelState.discoveredRoomOrder).toEqual([
"room.level1.start",
"room.level1.small.002",
]);
expect(result.fromRoom.exits[0]?.leadsToRoomId).toBe("room.level1.small.002");
expect(result.createdRoom.exits.some((exit) => exit.leadsToRoomId === "room.level1.start")).toBe(
true,
);
});
it("rejects placement into an occupied coordinate", () => {
const levelState = initializeDungeonLevel({ content: sampleContentPack });
const expanded = expandLevelFromExit({
content: sampleContentPack,
levelState,
fromRoomId: "room.level1.start",
exitDirection: "north",
roomTableCode: "L1SR",
roomId: "room.level1.small.a",
roller: createSequenceRoller([3, 3]),
});
expect(() =>
expandLevelFromExit({
content: sampleContentPack,
levelState: expanded.levelState,
fromRoomId: "room.level1.start",
exitDirection: "north",
roomTableCode: "L1SR",
roomId: "room.level1.small.b",
roller: createSequenceRoller([4, 4]),
}),
).toThrow("already connected");
});
});