- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试 - 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本 - 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试 - 产品文档、UI 设计规范、各玩法 GDD / HANDOFF - 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
141 lines
4.2 KiB
TypeScript
141 lines
4.2 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
import { Board } from '../src/board';
|
|
import { Game } from '../src/game';
|
|
import { PointerInput } from '../src/input';
|
|
import type { CellDef } from '../src/types';
|
|
|
|
const c = (id: string, x: number, y: number, w = 1, h = 1, clue?: number): CellDef => ({ id, x, y, w, h, clue });
|
|
|
|
// 一横四格:a(1) b c d
|
|
function setup() {
|
|
const b = Board.fromCells([c('a', 0, 0, 1, 1, 1), c('b', 1, 0), c('c', 2, 0), c('d', 3, 0)]);
|
|
const g = new Game(b);
|
|
return { b, g, input: new PointerInput(g) };
|
|
}
|
|
|
|
test('按下起点后滑动追加;滑回上一格撤销;松手保留路径', () => {
|
|
const { g, input } = setup();
|
|
input.down(0);
|
|
assert.equal(g.path.length, 1);
|
|
input.move(1);
|
|
input.move(2);
|
|
assert.deepEqual([...g.path], [0, 1, 2]);
|
|
input.move(1); // 滑回上一格 = 撤销
|
|
assert.deepEqual([...g.path], [0, 1]);
|
|
input.up();
|
|
assert.equal(g.status, 'idle');
|
|
assert.deepEqual([...g.path], [0, 1]);
|
|
});
|
|
|
|
test('松手后从末端按下可继续;按不相邻的空格不生效', () => {
|
|
const { g, input } = setup();
|
|
input.down(0);
|
|
input.move(1);
|
|
input.up();
|
|
input.down(3); // 不相邻的空格
|
|
assert.equal(input.isDrawing, false);
|
|
input.move(2);
|
|
assert.equal(g.path.length, 2);
|
|
input.up();
|
|
input.down(1); // 末端
|
|
assert.equal(input.isDrawing, true);
|
|
input.move(2);
|
|
assert.deepEqual([...g.path], [0, 1, 2]);
|
|
});
|
|
|
|
test('点末端的前一格 = 撤销一步,且可以接着滑', () => {
|
|
const { g, input } = setup();
|
|
input.down(0);
|
|
input.move(1);
|
|
input.move(2);
|
|
input.up();
|
|
input.down(1);
|
|
assert.deepEqual([...g.path], [0, 1]);
|
|
assert.equal(input.isDrawing, true);
|
|
input.move(0);
|
|
assert.deepEqual([...g.path], [0]);
|
|
});
|
|
|
|
test('点末端旁边的空格直接追加(点着走)', () => {
|
|
const { g, input } = setup();
|
|
input.down(0);
|
|
input.up();
|
|
input.down(1);
|
|
assert.deepEqual([...g.path], [0, 1]);
|
|
});
|
|
|
|
test('有线索 1 时点别的格起手无效并产生 rejectStart', () => {
|
|
const { g, input } = setup();
|
|
const ev = input.down(2);
|
|
assert.equal(ev[0].type, 'rejectStart');
|
|
assert.equal(g.path.length, 0);
|
|
assert.equal(input.isDrawing, false);
|
|
assert.deepEqual(input.move(1), []);
|
|
});
|
|
|
|
test('滑到不相邻格忽略;空白 -1 不影响;同一格不重复触发', () => {
|
|
const { g, input } = setup();
|
|
input.down(0);
|
|
input.move(-1);
|
|
input.move(2); // 不相邻
|
|
assert.deepEqual([...g.path], [0]);
|
|
input.move(1);
|
|
input.move(1);
|
|
assert.deepEqual([...g.path], [0, 1]);
|
|
});
|
|
|
|
test('过关后停止响应', () => {
|
|
const { g, input } = setup();
|
|
input.down(0);
|
|
input.move(1);
|
|
input.move(2);
|
|
const ev = input.move(3);
|
|
assert.ok(ev.some((e) => e.type === 'cleared'));
|
|
assert.equal(input.isDrawing, false);
|
|
assert.deepEqual(input.down(3), []);
|
|
assert.deepEqual(input.move(2), []);
|
|
assert.equal(g.path.length, 4);
|
|
});
|
|
|
|
test('点更早的历史格一次撤掉多步,不松手即可沿新分支继续', () => {
|
|
const b = Board.fromCells([
|
|
c('a', 0, 0, 1, 1, 1), c('b', 1, 0), c('c', 2, 0),
|
|
c('d', 2, 1), c('e', 1, 1), c('f', 0, 1),
|
|
]);
|
|
const g = new Game(b);
|
|
const input = new PointerInput(g);
|
|
input.down(0);
|
|
[1, 2, 3, 4].forEach(cell => input.move(cell));
|
|
input.up();
|
|
const events = input.down(1);
|
|
assert.deepEqual(g.path, [0, 1]);
|
|
assert.deepEqual(events, [
|
|
{ type: 'unstep', cell: 4, step: 5 },
|
|
{ type: 'unstep', cell: 3, step: 4 },
|
|
{ type: 'unstep', cell: 2, step: 3 },
|
|
{ type: 'rewound', cell: 1, removed: 3 },
|
|
]);
|
|
assert.equal(input.isDrawing, true);
|
|
assert.equal(g.status, 'drawing');
|
|
input.move(4); // 从第 2 格直接转入之前的第 5 格
|
|
input.move(5);
|
|
input.up();
|
|
assert.deepEqual(g.path, [0, 1, 4, 5]);
|
|
assert.equal(g.stepOf(4), 3);
|
|
assert.equal(g.stepOf(2), 0);
|
|
assert.equal(g.status, 'idle');
|
|
});
|
|
|
|
test('不松手滑到不相邻历史格可直接回退;同格抖动不会重复撤销', () => {
|
|
const { g, input } = setup();
|
|
input.down(0);
|
|
input.move(1);
|
|
input.move(2);
|
|
input.move(0); // 与末端不相邻,仍能一次回到起点
|
|
assert.deepEqual(g.path, [0]);
|
|
assert.deepEqual(input.move(0), []);
|
|
input.move(1);
|
|
assert.deepEqual(g.path, [0, 1]);
|
|
});
|