Browse Source

fix(chase): align round generator output with snapshot contract

Made-with: Cursor
master
npmrun 2 weeks ago
parent
commit
448de36651
  1. 39
      src/game/chase/generator.ts
  2. 32
      tests/chase/chaseGenerator.test.ts

39
src/game/chase/generator.ts

@ -12,9 +12,17 @@ export interface GenerateChaseRoundInput {
} }
export interface ChaseRound { export interface ChaseRound {
graph: GameGraph; snapshot: {
startNodeId: NodeId; seed: number;
exitNodeId: NodeId; difficulty: Difficulty;
graph: GameGraph;
thiefStartNodeId: NodeId;
guardStartNodeId: NodeId;
thiefNodeId: NodeId;
guardNodeId: NodeId;
exitNodeId: NodeId;
status: "playing";
};
meta: { meta: {
hasEscapePath: boolean; hasEscapePath: boolean;
pathLength: number; pathLength: number;
@ -160,15 +168,26 @@ function generateGraphAttempt(seed: number, difficulty: Difficulty): ChaseRound
edgeList: buildEdgeList(nodes), edgeList: buildEdgeList(nodes),
}; };
const startNodeId = existingNodeIds[randomInt(rng, 0, existingNodeIds.length - 1)]; const thiefStartNodeId =
const farthest = getFarthestNode(graph, startNodeId); existingNodeIds[randomInt(rng, 0, existingNodeIds.length - 1)];
const farthest = getFarthestNode(graph, thiefStartNodeId);
const exitNodeId = farthest.id; const exitNodeId = farthest.id;
const pathLength = shortestPathLength(graph, startNodeId, exitNodeId); const pathLength = shortestPathLength(graph, thiefStartNodeId, exitNodeId);
const farthestFromExit = getFarthestNode(graph, exitNodeId);
const guardStartNodeId = farthestFromExit.id;
return { return {
graph, snapshot: {
startNodeId, seed,
exitNodeId, difficulty,
graph,
thiefStartNodeId,
guardStartNodeId,
thiefNodeId: thiefStartNodeId,
guardNodeId: guardStartNodeId,
exitNodeId,
status: "playing",
},
meta: { meta: {
hasEscapePath: Number.isFinite(pathLength) && pathLength > 0, hasEscapePath: Number.isFinite(pathLength) && pathLength > 0,
pathLength, pathLength,
@ -185,7 +204,7 @@ export function generateChaseRound(input: GenerateChaseRoundInput): ChaseRound {
const attemptSeed = normalizeSeed(baseSeed + attempt * 0x9e3779b9); const attemptSeed = normalizeSeed(baseSeed + attempt * 0x9e3779b9);
const round = generateGraphAttempt(attemptSeed, input.difficulty); const round = generateGraphAttempt(attemptSeed, input.difficulty);
const isPlayable = const isPlayable =
isConnected(round.graph) && isConnected(round.snapshot.graph) &&
round.meta.hasEscapePath && round.meta.hasEscapePath &&
round.meta.pathLength >= minPathLength; round.meta.pathLength >= minPathLength;

32
tests/chase/chaseGenerator.test.ts

@ -16,14 +16,21 @@ describe("chase round generator", () => {
const round = generateChaseRound({ seed: 424242, difficulty: "easy" }); const round = generateChaseRound({ seed: 424242, difficulty: "easy" });
expect({ expect({
startNodeId: round.startNodeId, seed: round.snapshot.seed,
exitNodeId: round.exitNodeId, difficulty: round.snapshot.difficulty,
thiefStartNodeId: round.snapshot.thiefStartNodeId,
guardStartNodeId: round.snapshot.guardStartNodeId,
thiefNodeId: round.snapshot.thiefNodeId,
guardNodeId: round.snapshot.guardNodeId,
exitNodeId: round.snapshot.exitNodeId,
status: round.snapshot.status,
hasEscapePath: round.meta.hasEscapePath, hasEscapePath: round.meta.hasEscapePath,
nodeCount: Object.keys(round.graph.nodes).length, nodeCount: Object.keys(round.snapshot.graph.nodes).length,
edgeCount: round.graph.edgeList.length, edgeCount: round.snapshot.graph.edgeList.length,
firstFiveNodeIds: Object.keys(round.graph.nodes).slice(0, 5), firstFiveNodeIds: Object.keys(round.snapshot.graph.nodes).slice(0, 5),
}).toMatchInlineSnapshot(` }).toMatchInlineSnapshot(`
{ {
"difficulty": "easy",
"edgeCount": 19, "edgeCount": 19,
"exitNodeId": "0,-1", "exitNodeId": "0,-1",
"firstFiveNodeIds": [ "firstFiveNodeIds": [
@ -33,16 +40,21 @@ describe("chase round generator", () => {
"2,-1", "2,-1",
"1,-2", "1,-2",
], ],
"guardNodeId": "4,-5",
"guardStartNodeId": "4,-5",
"hasEscapePath": true, "hasEscapePath": true,
"nodeCount": 20, "nodeCount": 20,
"startNodeId": "4,-5", "seed": 424242,
"status": "playing",
"thiefNodeId": "4,-5",
"thiefStartNodeId": "4,-5",
} }
`); `);
}); });
it("generates graph node count between 20 and 30", () => { it("generates graph node count between 20 and 30", () => {
const round = generateChaseRound({ seed: 11, difficulty: "normal" }); const round = generateChaseRound({ seed: 11, difficulty: "normal" });
const nodeCount = Object.keys(round.graph.nodes).length; const nodeCount = Object.keys(round.snapshot.graph.nodes).length;
expect(nodeCount).toBeGreaterThanOrEqual(20); expect(nodeCount).toBeGreaterThanOrEqual(20);
expect(nodeCount).toBeLessThanOrEqual(30); expect(nodeCount).toBeLessThanOrEqual(30);
}); });
@ -50,9 +62,9 @@ describe("chase round generator", () => {
it("ensures an escape path exists", () => { it("ensures an escape path exists", () => {
const round = generateChaseRound({ seed: 99, difficulty: "hard" }); const round = generateChaseRound({ seed: 99, difficulty: "hard" });
const pathLength = shortestPathLength( const pathLength = shortestPathLength(
round.graph, round.snapshot.graph,
round.startNodeId, round.snapshot.thiefNodeId,
round.exitNodeId, round.snapshot.exitNodeId,
); );
expect(round.meta.hasEscapePath).toBe(true); expect(round.meta.hasEscapePath).toBe(true);

Loading…
Cancel
Save