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

54 lines
1.9 KiB
TypeScript

// 终端字符盘面:点顶六边形按行错位显示。每格 4 字符宽,相邻行错开 2 字符。
import type { HexBoard } from '../src/board';
export function renderAscii(board: HexBoard, path?: number[]): string {
const stepOf = new Map<number, number>();
if (path) path.forEach((c, i) => stepOf.set(c, i + 1));
let minR = Infinity;
let maxR = -Infinity;
let minX = Infinity;
for (const c of board.cells) {
minR = Math.min(minR, c.r);
maxR = Math.max(maxR, c.r);
minX = Math.min(minX, 2 * c.q + c.r);
}
const lines: string[] = [];
for (let r = minR; r <= maxR; r++) {
const row = board.cells.filter((c) => c.r === r).sort((a, b) => a.q - b.q);
let line = '';
for (const c of row) {
const col = (2 * c.q + c.r - minX) * 2;
while (line.length < col) line += ' ';
let tok: string;
if (path) {
const s = stepOf.get(c.index);
tok = s === undefined ? ' . ' : String(s).padStart(2) + ' ';
if (c.clue !== null && s !== undefined) tok = String(s).padStart(2) + (s === c.clue ? '*' : '!');
} else {
tok = c.clue !== null ? `[${c.clue}]`.padStart(3) : ` ${c.id.slice(0, 2).padEnd(2)}`;
}
line += tok.padEnd(4);
}
lines.push(line.replace(/\s+$/, ''));
}
if (board.walls.length) {
lines.push('墙: ' + board.walls.map((w) => `${board.cells[w.a].id}|${board.cells[w.b].id}`).join(' '));
}
if (board.spinners.length) {
lines.push(
'转墙: ' +
board.spinners
.map((sp) => {
const e = sp.edges.map((x) => (x ? `${board.cells[x[0]].id}|${board.cells[x[1]].id}` : '外')).join(' → ');
return `${board.cells[sp.cell].id}/${sp.corner} 相位${sp.phase} [${e}]`;
})
.join(' '),
);
}
return lines.join('\n');
}
export function pathToIds(board: HexBoard, path: number[]): string {
return path.map((i) => board.cells[i].id).join(',');
}