Add map state module with createMap, advanceMap, getCurrentNode

This commit is contained in:
Jared Miller 2026-02-25 09:52:22 -05:00
parent 4f91396e3a
commit a7c5cbc56a
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
2 changed files with 116 additions and 0 deletions

35
src/map.js Normal file
View file

@ -0,0 +1,35 @@
const ACT1_LAYOUT = [
"encounter",
"encounter",
"campfire",
"encounter",
"elite",
"encounter",
"campfire",
"encounter",
"elite",
"boss",
];
export function createMap() {
return {
nodes: ACT1_LAYOUT.map((type, id) => ({ id, type, cleared: false })),
currentNode: 0,
};
}
export function advanceMap(map) {
const last = map.nodes.length - 1;
const nodes = map.nodes.map((n, i) =>
i === map.currentNode ? { ...n, cleared: true } : n,
);
return {
...map,
nodes,
currentNode: Math.min(map.currentNode + 1, last),
};
}
export function getCurrentNode(map) {
return map.nodes[map.currentNode];
}

81
src/map.test.js Normal file
View file

@ -0,0 +1,81 @@
import { describe, expect, test } from "bun:test";
import { advanceMap, createMap, getCurrentNode } from "./map.js";
describe("createMap", () => {
test("returns 10 nodes", () => {
const map = createMap();
expect(map.nodes).toHaveLength(10);
});
test("first node is encounter, last node is boss", () => {
const map = createMap();
expect(map.nodes[0].type).toBe("encounter");
expect(map.nodes[9].type).toBe("boss");
});
test("contains expected node type counts", () => {
const map = createMap();
const types = map.nodes.map((n) => n.type);
expect(types.filter((t) => t === "encounter")).toHaveLength(5);
expect(types.filter((t) => t === "campfire")).toHaveLength(2);
expect(types.filter((t) => t === "elite")).toHaveLength(2);
expect(types.filter((t) => t === "boss")).toHaveLength(1);
});
test("all nodes start cleared: false", () => {
const map = createMap();
expect(map.nodes.every((n) => n.cleared === false)).toBe(true);
});
test("each node has sequential id 0-9", () => {
const map = createMap();
map.nodes.forEach((n, i) => {
expect(n.id).toBe(i);
});
});
test("currentNode starts at 0", () => {
const map = createMap();
expect(map.currentNode).toBe(0);
});
});
describe("advanceMap", () => {
test("marks current node cleared and increments currentNode", () => {
const map = createMap();
const next = advanceMap(map);
expect(next.nodes[0].cleared).toBe(true);
expect(next.currentNode).toBe(1);
});
test("does not mutate the input map", () => {
const map = createMap();
advanceMap(map);
expect(map.nodes[0].cleared).toBe(false);
expect(map.currentNode).toBe(0);
});
test("does not go past last node (index 9)", () => {
let map = createMap();
for (let i = 0; i < 10; i++) {
map = advanceMap(map);
}
expect(map.currentNode).toBe(9);
});
});
describe("getCurrentNode", () => {
test("returns the node at currentNode index", () => {
const map = createMap();
const node = getCurrentNode(map);
expect(node).toBe(map.nodes[map.currentNode]);
expect(node.id).toBe(0);
expect(node.type).toBe("encounter");
});
test("returns correct node after advancing", () => {
const map = advanceMap(createMap());
const node = getCurrentNode(map);
expect(node.id).toBe(1);
});
});