// 关卡地图工具:让手工 ASCII 不必逐格数点 // G(w, rows) —— 每行不足宽度自动补 '.',最后一列强制为 '#'(外墙) export function G(w, rows) { return rows.map(r => { const s = r.length >= w ? r.slice(0, w) : r + '.'.repeat(w - r.length); return s.slice(0, w - 1) + '#'; }); } // 重复字符:rep('%', 20) export const rep = (ch, n) => ch.repeat(Math.max(0, n | 0)); // 空格行 export const E = w => '#' + rep('.', w - 2); // 实心跳台:plat(w, 起列, 长度) => 一行带 '#####' 的字符串 export function plat(w, x0, len, ch = '#') { if (x0 < 1) x0 = 1; return '#' + rep('.', x0 - 1) + rep(ch, len); } // 实体行:ent(w, [列, 字符], ...) => 一行只在指定列放实体字符 export function ent(w, ...items) { const a = new Array(w).fill('.'); a[0] = '#'; for (const [x, ch] of items) if (x > 0 && x < w - 1) a[x] = ch; return a.join(''); } // 地板行:从 col1 开始按 [字符, 长度] 铺满,最后一列由 G 补 '#' export function flr(...parts) { let s = '#'; for (const [ch, n] of parts) s += rep(ch, n); return s; } // ---------------- 2D 网格构建器 ---------------- // 大地图用拼字符串极易出错(宽度对不齐 / 数错列),改用网格对象: // const m = new Map(120, 30); m.rect(x,y,w,h,'#'); ... m.out() export class Grid { constructor(w, h, fill = '.') { this.w = w; this.h = h; this.g = Array.from({ length: h }, () => new Array(w).fill(fill)); } set(x, y, ch) { if (x >= 0 && x < this.w && y >= 0 && y < this.h) this.g[y][x] = ch; return this; } rect(x, y, w, h, ch) { for (let iy = y; iy < y + h; iy++) for (let ix = x; ix < x + w; ix++) this.set(ix, iy, ch); return this; } hline(y, x0, x1, ch) { for (let x = x0; x <= x1; x++) this.set(x, y, ch); return this; } vline(x, y0, y1, ch) { for (let y = y0; y <= y1; y++) this.set(x, y, ch); return this; } border(ch = '#') { this.hline(0, 0, this.w - 1, ch); this.hline(this.h - 1, 0, this.w - 1, ch); this.vline(0, 0, this.h - 1, ch); this.vline(this.w - 1, 0, this.h - 1, ch); return this; } out() { return this.g.map(r => r.join('')); } } /** 落脚台序列:chain(起始列, 起始宽, [间隙...], 台宽) => [{x,w}, ...] */ export function chain(x0, w0, gaps, padW = 2) { const out = [{ x: x0, w: w0 }]; let x = x0 + w0; for (const g of gaps) { x += g; out.push({ x, w: padW }); x += padW; } return out; }