From fdffd8c3d822400205be290f9eeeae530f45f8e6 Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Mon, 27 Apr 2026 00:06:12 +0800 Subject: [PATCH] fix(chase): align endgame text and round transition semantics Made-with: Cursor --- src/stages/page_chase.ts | 2 +- tests/chase/chaseModel.test.ts | 40 ++++++++++++++++++++++++++++++++++++++++ tests/stages/page_chase.test.ts | 6 +++++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/stages/page_chase.ts b/src/stages/page_chase.ts index 5ecb3b9..e87b977 100644 --- a/src/stages/page_chase.ts +++ b/src/stages/page_chase.ts @@ -452,7 +452,7 @@ export default class ChaseScene extends BaseScene { return; } - this.resultText.text = loseReason === "trapped" ? "无路可走" : "被抓住"; + this.resultText.text = loseReason === "trapped" ? "你已无路可走" : "你被抓住了"; this.restartButton.visible = false; this.retryButton.visible = true; this.newGameButton.visible = true; diff --git a/tests/chase/chaseModel.test.ts b/tests/chase/chaseModel.test.ts index c74d3d2..a1aa38c 100644 --- a/tests/chase/chaseModel.test.ts +++ b/tests/chase/chaseModel.test.ts @@ -173,6 +173,23 @@ describe("chase game model", () => { expect(mockedGenerateChaseRound).toHaveBeenCalledTimes(1); }); + it("retryRound keeps exactly same graph and start positions", () => { + mockedGenerateChaseRound.mockReturnValueOnce(makeRound(88, "normal")); + const model = ChaseGameModel.createWithSeed({ seed: 88, difficulty: "normal" }); + const initial = model.getState().snapshot; + + model.moveThief("A"); + model.retryRound(); + const retried = model.getState().snapshot; + + expect(retried.graph).toEqual(initial.graph); + expect(retried.thiefStartNodeId).toBe(initial.thiefStartNodeId); + expect(retried.guardStartNodeId).toBe(initial.guardStartNodeId); + expect(retried.exitNodeId).toBe(initial.exitNodeId); + expect(retried.thiefNodeId).toBe(initial.thiefNodeId); + expect(retried.guardNodeId).toBe(initial.guardNodeId); + }); + it("newRound switches seed/difficulty and keeps winCount", () => { mockedGenerateChaseRound .mockReturnValueOnce(makeRound(55, "easy")) @@ -204,6 +221,29 @@ describe("chase game model", () => { expect(state.snapshot.difficulty).toBe("easy"); }); + it("newRound with new seed produces a new round snapshot", () => { + const base = makeRound(300, "normal"); + const next = makeRound(301, "normal"); + next.snapshot.graph.nodes.E = { id: "E", q: 4, r: 0, neighbors: [] }; + next.snapshot.thiefStartNodeId = "A"; + next.snapshot.guardStartNodeId = "C"; + next.snapshot.exitNodeId = "D"; + next.snapshot.thiefNodeId = "A"; + next.snapshot.guardNodeId = "C"; + + mockedGenerateChaseRound.mockReturnValueOnce(base).mockReturnValueOnce(next); + const model = ChaseGameModel.createWithSeed({ seed: 300, difficulty: "normal" }); + const before = model.getState().snapshot; + + model.newRound(301, "normal"); + const after = model.getState().snapshot; + + expect(after.seed).toBe(301); + expect(after).not.toEqual(before); + expect(Object.keys(after.graph.nodes)).toContain("E"); + expect(after.thiefStartNodeId).toBe("A"); + }); + it("retryRound resets rng so same move sequence is reproducible", () => { const easyRound = { snapshot: { diff --git a/tests/stages/page_chase.test.ts b/tests/stages/page_chase.test.ts index 0122084..9e03996 100644 --- a/tests/stages/page_chase.test.ts +++ b/tests/stages/page_chase.test.ts @@ -295,6 +295,7 @@ describe("chase stage skeleton", () => { model: { getState, moveThief: vi.fn(), newRound, retryRound: vi.fn() } as any, }); void (scene as any).onSceneLayout(); + (scene as any).difficultyButtons.hard.emit("pointerdown"); expect((scene as any).resultOverlay.visible).toBe(true); expect((scene as any).resultText.text).toContain("成功逃脱"); @@ -302,6 +303,7 @@ describe("chase stage skeleton", () => { (scene as any).restartButton.emit("pointerdown"); (scene as any).restartButton.emit("pointerdown"); expect(newRound).toHaveBeenCalledTimes(1); + expect(newRound.mock.calls[0][1]).toBe("hard"); }); it("shows lose overlay and retry/new buttons call correct model methods", () => { @@ -324,7 +326,7 @@ describe("chase stage skeleton", () => { } as any, }); void (retryScene as any).onSceneLayout(); - expect((retryScene as any).resultText.text).toContain("无路可走"); + expect((retryScene as any).resultText.text).toContain("你已无路可走"); (retryScene as any).retryButton.emit("pointerdown"); (retryScene as any).retryButton.emit("pointerdown"); expect(retryRound).toHaveBeenCalledTimes(1); @@ -339,8 +341,10 @@ describe("chase stage skeleton", () => { } as any, }); void (newGameScene as any).onSceneLayout(); + (newGameScene as any).difficultyButtons.easy.emit("pointerdown"); (newGameScene as any).newGameButton.emit("pointerdown"); (newGameScene as any).newGameButton.emit("pointerdown"); expect(newRound).toHaveBeenCalledTimes(1); + expect(newRound.mock.calls[0][1]).toBe("easy"); }); });