Files
NumberSwipe_New/modes/01-number-stroke/tests/layout.test.ts
T
cabinw 8026e4628d 初始提交:三玩法 Web 原型与设计文档
- 玩法一 数字一笔:规则库、求解器、26 关、竖屏触摸 Web 原型、测试
- 玩法二 连连气球:连消畅玩版核心、Web 原型、Cocos 球槽组件与导出脚本
- 玩法三 六边一笔:规则库、求解器、10 关 + 转墙实验包、Web 原型、测试
- 产品文档、UI 设计规范、各玩法 GDD / HANDOFF
- 文档移除全部外部参考作引用;删除玩法二 v0 旧稿
2026-09-16 14:30:59 +08:00

77 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { Board } from '../src/board';
import { bridgeRect, cellRect, cellShapeRects, fitBoard, hitTest } from '../src/layout';
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 });
test('按短边缩放并居中,受 maxUnit 限制', () => {
const b = Board.fromCells([c('a', 0, 0), c('b', 1, 0), c('c', 2, 0)]);
const L = fitBoard(b, 390, 600, { padding: 10, maxUnit: 96 });
assert.equal(L.unit, 96);
assert.equal(L.width, 288);
assert.equal(L.originX, (390 - 288) / 2);
const tall = Board.fromCells([c('a', 0, 0), c('b', 0, 1), c('c', 0, 2), c('d', 0, 3), c('e', 0, 4), c('f', 0, 5)]);
const L2 = fitBoard(tall, 390, 300, { padding: 0, maxUnit: 200 });
assert.equal(L2.unit, 50);
});
test('命中测试:格中心命中、缝与死区不命中、空洞不命中', () => {
const b = Board.fromCells([c('a', 0, 0), c('B', 1, 0, 2, 2), c('h', 0, 2)]);
const L = fitBoard(b, 300, 300, { padding: 0, maxUnit: 100 });
const ra = cellRect(b, 0, L);
assert.equal(hitTest(b, L, ra.x + ra.w / 2, ra.y + ra.h / 2), 0);
assert.equal(hitTest(b, L, L.originX + 2, L.originY + 2), -1, '角落死区');
assert.equal(hitTest(b, L, L.originX + 150, L.originY + 150), 1, '2×2 中心');
assert.equal(hitTest(b, L, L.originX + 50, L.originY + 150), -1, '空洞 (0,1)');
assert.equal(hitTest(b, L, -5, -5), -1);
});
test('桥矩形横跨缝并落在共享边中点', () => {
const b = Board.fromCells([c('a', 0, 0), c('B', 1, 0, 2, 2)]);
const L = fitBoard(b, 300, 200, { padding: 0, maxUnit: 100 });
const br = bridgeRect(b, 0, 1, L)!;
assert.ok(br);
assert.ok(Math.abs(br.x + br.w / 2 - (L.originX + 100)) < 1e-6, '中心在 x=1 的边上');
assert.ok(Math.abs(br.y + br.h / 2 - (L.originY + 50)) < 1e-6, '共享边 y∈[0,1] 的中点');
assert.equal(bridgeRect(b, 1, 1, L), null);
});
test('异形格绘制矩形:单位 + 接缝', () => {
// L4 占 (1,1)(1,2)(1,3)(2,3):4 个单位矩形 + 3 条内部缝(两竖一横)
// 补一个 (0,0) 的格钉住原点,免得 L 被平移
const b = Board.fromCells([
{ id: 'L', x: 1, y: 1, w: 2, h: 3, shape: [[0, 0], [0, 1], [0, 2], [1, 2]] },
c('z', 0, 0),
]);
const L = fitBoard(b, 300, 300, { padding: 0, maxUnit: 100 });
const { units, seams } = cellShapeRects(b, 0, L);
assert.equal(units.length, 4);
assert.equal(seams.length, 3);
const half = L.gap / 2;
// 横缝:(1,3)→(2,3),跨过 x=2 的竖缝,向两侧单位内各延长一个圆角半径(盖住圆角缺口)
assert.deepEqual(
seams.find((r) => r.w === L.gap + 2 * L.radius),
{
x: L.originX + 2 * L.unit - half - L.radius,
y: L.originY + 3 * L.unit + half,
w: L.gap + 2 * L.radius,
h: L.unit - L.gap,
},
);
// 竖缝:(1,1)→(1,2),跨过 y=2 的横缝,同样上下延长
assert.deepEqual(
seams.find((r) => r.h === L.gap + 2 * L.radius && r.y === L.originY + 2 * L.unit - half - L.radius),
{
x: L.originX + L.unit + half,
y: L.originY + 2 * L.unit - half - L.radius,
w: L.unit - L.gap,
h: L.gap + 2 * L.radius,
},
);
// 单位矩形与 cellRect 对单个 1×1 的算法一致
const u0 = units[0];
assert.deepEqual(u0, { x: L.originX + L.unit + half, y: L.originY + L.unit + half, w: L.unit - L.gap, h: L.unit - L.gap });
});