Files
ai-coding-workflow-labs/superpowers/tests/game/pathfinder.test.js
T
tiennm99 51a4b90163 refactor: migrate quiz-project, gstack, and superpowers to JS+JSDoc
Convert all 41 TypeScript source/config files in cc4e-course/quiz-project
(Next.js), gstack (Astro), and superpowers (Vite/React/Phaser) to plain
JavaScript with JSDoc type annotations, replacing tsconfig.json with
jsconfig.json (strict + checkJs) in each subproject. No behavior changes:
lint, typecheck, test, and build gates match their TypeScript baselines
exactly in all three subprojects. Update stack references in the affected
READMEs accordingly.
2026-08-18 09:49:42 +07:00

119 lines
3.2 KiB
JavaScript

import { describe, it, expect } from "vitest";
import { findPath, hasAnyValidMove } from "../../src/game/pathfinder";
/** @typedef {import("../../src/types").Board} Board */
/**
* @param {(string | null)[][]} grid
* @returns {Board}
*/
function makeBoard(grid) {
let id = 0;
return grid.map((row) =>
row.map((cell) => (cell !== null ? { emoji: cell, id: id++ } : null))
);
}
describe("findPath", () => {
it("finds direct horizontal connection", () => {
const board = makeBoard([
["A", null, "A"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 0, col: 2 });
expect(path).not.toBeNull();
expect(/** @type {NonNullable<typeof path>} */ (path).length).toBe(2);
});
it("finds direct vertical connection", () => {
const board = makeBoard([
["A"],
[null],
["A"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 2, col: 0 });
expect(path).not.toBeNull();
expect(/** @type {NonNullable<typeof path>} */ (path).length).toBe(2);
});
it("finds one-bend connection", () => {
const board = makeBoard([
["A", null],
[null, "A"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 1, col: 1 });
expect(path).not.toBeNull();
expect(/** @type {NonNullable<typeof path>} */ (path).length).toBe(3);
});
it("finds two-bend connection", () => {
const board = makeBoard([
["A", "B", null],
[null, null, null],
[null, "B", "A"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 2, col: 2 });
expect(path).not.toBeNull();
expect(/** @type {NonNullable<typeof path>} */ (path).length).toBe(4);
});
it("returns null when no valid path exists", () => {
const board = makeBoard([
["A", "B", "C"],
["D", "E", "F"],
["C", "B", "A"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 2, col: 2 });
expect(path).toBeNull();
});
it("returns null when tiles are not the same emoji", () => {
const board = makeBoard([
["A", null, "B"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 0, col: 2 });
expect(path).toBeNull();
});
it("finds path through border (empty surround)", () => {
const board = makeBoard([
["A", "B", "A"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 0, col: 2 });
expect(path).not.toBeNull();
});
it("adjacent identical tiles connect", () => {
const board = makeBoard([
["A", "A"],
]);
const path = findPath(board, { row: 0, col: 0 }, { row: 0, col: 1 });
expect(path).not.toBeNull();
expect(/** @type {NonNullable<typeof path>} */ (path).length).toBe(2);
});
});
describe("hasAnyValidMove", () => {
it("returns true when moves exist", () => {
const board = makeBoard([
["A", "A"],
]);
expect(hasAnyValidMove(board)).toBe(true);
});
it("returns false when no moves exist", () => {
const board = makeBoard([
["A", "B"],
["C", "D"],
]);
expect(hasAnyValidMove(board)).toBe(false);
});
it("returns false for empty board", () => {
const board = makeBoard([
[null, null],
[null, null],
]);
expect(hasAnyValidMove(board)).toBe(false);
});
});