// 跳刺(Needle)10 关 —— IWBT 经典密集针刺风格 // 设计语法(已经 tools/solve.mjs 验证): // 刺毯缺口每 4 格一个(单跳节奏);钻石中心 = 地板上方 2~3 格; // 垂刺离最低落脚点 5 格(单跳安全、二段跳必死);2 格高矮洞可用撞头跳; // 竖井台阶每级升 2~3 格横移 3 格内;钢丝柱间距 ≤4(单跳)/ ≤6(二段)。 import { Grid } from './kit.js'; import { vgap, hgap, diamond, spikeRun, block, corner, ceil, wall, well } from './needle.js'; // 刺毯:从 x0 起 n 格留落脚缺口。 // 缺口间距在 4/3 格之间交替(跳 3 格 / 跳 4 格轮换),避免整关都是"每 4 格一跳"的单一套路; // 最远仍是 3 连刺(单跳极限),配合压顶垂刺时二段跳必死。 const carpet = (m, x0, y, n, gaps = []) => { const g = []; let i = 3, k = 0; while (i < n) { g.push(i); i += (k++ % 2 === 0 ? 4 : 3); } return spikeRun(m, x0, y, n, '^', g.concat(gaps)); }; export const JUMP_LEVELS = [ // ============================================================ j1 刺巷 { id: 'j1', name: 'SPIKE ALLEY', cn: '刺巷', type: 'jump', diff: 2, hint: '针刺入门:刺毯单跳节奏、钻石缝、矮洞撞头跳、竖井、对刺门。', width: 104, grid: (() => { const W = 104, H = 26, R = 22; const m = new Grid(W, H); m.border('#'); m.rect(1, R, W - 2, 1, '#'); // 主地板 // --- x1-9 起步 --- m.set(3, R - 1, 'S'); m.set(8, R - 1, 'G'); // --- x10-26 刺毯(单跳节奏,垂刺压顶禁二段,两道上下夹缝)--- carpet(m, 10, R - 1, 17); ceil(m, 10, 26, R - 6); vgap(m, 15, R - 2); vgap(m, 21, R - 2); // --- x28-43 钻石门三连(中心 R-2,单跳穿缝)--- carpet(m, 28, R - 1, 16, [0, 4, 8, 12, 15]); // 加密缺口便于站位 ceil(m, 28, 43, R - 6); vgap(m, 30, R - 2); vgap(m, 34, R - 2); vgap(m, 38, R - 2); m.set(28, R - 1, 'G'); // --- x44-56 矮洞(顶 row 18,3 格高,撞头跳 + 对刺门)--- m.rect(44, R - 4, 13, 1, '#'); carpet(m, 45, R - 1, 11); hgap(m, 48, R - 1); hgap(m, 53, R - 1); m.set(45, R - 1, 'G'); // --- x57-71 刺坑上的钢丝柱 --- for (let x = 57; x <= 70; x++) { m.set(x, R, '.'); m.set(x, R + 1, '^'); } const wires = [[58, 20], [61, 19], [64, 20], [67, 18], [70, 20]]; for (const [x, top] of wires) m.vline(x, top, R - 1, '#'); m.set(72, R - 1, 'G'); // --- x74-79 竖井上上层(井底留 3 格入口)--- m.vline(74, R - 10, R - 4, '#'); m.vline(79, R - 12, R - 1, '#'); block(m, 75, R - 3, 2); // 19 block(m, 77, R - 6, 2); // 16 block(m, 75, R - 9, 2); // 13 wall(m, 79, R - 5, R - 5, '<'); wall(m, 74, R - 7, R - 7, '>'); // --- 上层回廊(地板 row 12)x80-97 --- m.rect(80, R - 10, 18, 1, '#'); carpet(m, 81, R - 11, 15, [0]); ceil(m, 81, 95, R - 16); // row 6 垂刺 hgap(m, 92, R - 11); // 对刺门 m.set(82, R - 11, 'G'); m.set(94, R - 11, 'G'); // --- x98-102 下落井 + 终点 --- wall(m, 99, R - 7, R - 3, '>'); wall(m, 102, R - 5, R - 2, '<'); m.set(100, R - 1, 'X'); return m.out(); })(), }, // ============================================================ j2 垂直地狱 { id: 'j2', name: 'VERTICAL HELL', cn: '垂直地狱', type: 'jump', diff: 3, hint: '52 格高塔:四段之字竖井,每层刺毯+上下夹缝,垂刺压顶、掉落刺追身。', width: 68, grid: (() => { const W = 68, H = 52; const m = new Grid(W, H); m.border('#'); // ---- L0 地板 row 48(向右:刺毯 + 三道上下夹缝)---- m.rect(1, 48, 66, 1, '#'); m.set(3, 47, 'S'); carpet(m, 5, 47, 50); ceil(m, 5, 54, 43); vgap(m, 16, 46); vgap(m, 30, 46); vgap(m, 46, 46); m.set(11, 47, 'G'); m.set(39, 47, 'G'); // ---- 右井 x58..65:L0 → L1(井底 3 格敞口,之字每级升 2 格)---- well(m, 58, 65, 40, 48, 'l'); m.set(65, 45, '^'); m.set(58, 43, '^'); // 踏石外沿刺,逼迫精准落点 // ---- L1 地板 row 40(向左;垂刺避开左井 x2..9)---- m.rect(2, 40, 56, 1, '#'); carpet(m, 10, 39, 44); ceil(m, 10, 54, 35); vgap(m, 42, 38); vgap(m, 26, 38); vgap(m, 12, 38); m.set(47, 39, 'G'); m.set(19, 39, 'G'); // ---- 左井 x2..8:L1 → L2 ---- well(m, 2, 8, 32, 40, 'r'); m.set(2, 37, '^'); m.set(8, 35, '^'); // ---- L2 地板 row 32(向右,井底延伸到右井下方)---- m.rect(9, 32, 57, 1, '#'); carpet(m, 11, 31, 46); ceil(m, 11, 54, 27); hgap(m, 22, 31); hgap(m, 42, 31); vgap(m, 32, 30); vgap(m, 50, 30); m.set(19, 31, 'G'); m.set(47, 31, 'G'); // ---- 右井 x58..65:L2 → L3 ---- well(m, 58, 65, 24, 32, 'l'); m.set(65, 29, '^'); m.set(58, 27, '^'); // ---- L3 地板 row 24(向左,掉落刺;垂刺避开左井 x2..9)---- m.rect(2, 24, 56, 1, '#'); carpet(m, 10, 23, 44); ceil(m, 10, 54, 19); [14, 24, 34, 44].forEach(x => m.set(x, 18, 'D')); vgap(m, 40, 22); vgap(m, 22, 22); m.set(47, 23, 'G'); m.set(19, 23, 'G'); // ---- 左井 x2..8:L3 → L4 ---- well(m, 2, 8, 16, 24, 'r'); m.set(2, 21, '^'); m.set(8, 19, '^'); // ---- L4 地板 row 16(向右到终点)---- m.rect(9, 16, 57, 1, '#'); carpet(m, 11, 15, 52); ceil(m, 11, 60, 11); hgap(m, 26, 15); vgap(m, 40, 14); hgap(m, 52, 15); [18, 34, 56].forEach(x => m.set(x, 10, 'D')); m.set(27, 15, 'G'); m.set(51, 15, 'G'); m.set(62, 15, 'X'); return m.out(); })(), }, // ============================================================ j3 钢丝 { id: 'j3', name: 'TIGHTROPE', cn: '钢丝', type: 'jump', diff: 3, hint: '一格宽的柱子立在刺海上,高矮间距都不同,垂刺压着头顶。', width: 132, grid: (() => { const W = 132, H = 24, R = 20; const m = new Grid(W, H); m.border('#'); m.rect(1, R, W - 2, 1, '#'); // 基座 spikeRun(m, 4, R - 1, W - 6, '^'); // 刺海 // 钢丝柱(顶可站 1 格),高矮错落、间距 3~5 const cols = [ [4, 18], [8, 17], [12, 19], [15, 17], [19, 18], [23, 16], [27, 19], [30, 17], [34, 18], [38, 16], [42, 19], [46, 17], [50, 15], [54, 18], [58, 17], [62, 19], [66, 16], [70, 18], [74, 17], [78, 19], [82, 15], [86, 18], [90, 17], [94, 19], [98, 16], [102, 18], [106, 17], [110, 19], [114, 16], [118, 18], [122, 17], ]; for (const [x, top] of cols) m.vline(x, top, R - 1, '#'); // 起点/终点平台 m.rect(1, R - 1, 3, 1, '#'); m.set(2, R - 2, 'S'); m.rect(126, R - 1, 4, 1, '#'); m.set(128, R - 2, 'X'); // 垂刺段(离最低柱顶 5 格:单跳安全,二段跳死) ceil(m, 6, 28, 11); // 段内最低顶 16 ceil(m, 32, 56, 10); // 最低顶 15 ceil(m, 60, 88, 10); ceil(m, 92, 120, 11); // 存档(柱顶) m.set(23, 15, 'G'); m.set(58, 16, 'G'); m.set(90, 16, 'G'); m.set(122, 16, 'G'); return m.out(); })(), }, // ============================================================ j4 冰刺 { id: 'j4', name: 'ICE NEEDLES', cn: '冰刺', type: 'jump', diff: 4, hint: '冰面刹不住车:滑坑、冰上钻石、冰柱钢丝,最后还有一段冰顶矮洞。', width: 132, grid: (() => { const W = 132, H = 26, R = 22; const m = new Grid(W, H); m.border('#'); m.rect(1, R, W - 2, 1, '%'); // 冰地板 m.set(3, R - 1, 'S'); // --- x6-30 冰面刺坑 --- for (const [a, b] of [[7, 10], [13, 16], [19, 22], [25, 29]]) for (let x = a; x <= b; x++) { m.set(x, R, '.'); m.set(x, R + 1, '^'); } ceil(m, 6, 24, R - 5); // 压顶垂刺:冰面上禁二段跳 m.set(12, R - 1, 'G'); // --- x32-52 冰台阶 + 角刺 + 钻石 --- block(m, 33, R - 2, 2, '%'); block(m, 38, R - 2, 2); block(m, 43, R - 4, 2, '%'); ceil(m, 31, 52, R - 5); vgap(m, 48, R - 2); m.set(41, R - 1, 'G'); // --- x54-78 冰柱钢丝 --- spikeRun(m, 54, R - 1, 25, '^'); const ice = [[56, 19], [60, 18], [64, 20], [68, 17], [72, 19], [76, 18]]; for (const [x, top] of ice) m.vline(x, top, R - 1, '%'); ceil(m, 55, 77, 12); // 最低柱顶 17 → 12 m.set(64, 19, 'G'); // --- x80-100 冰顶矮洞(2 格高,撞头跳越刺)--- m.rect(80, R - 3, 21, 1, '%'); // 冰顶 row 19 spikeRun(m, 83, R - 1, 15, '^', [0, 4, 8, 12, 14]); m.set(81, R - 1, 'G'); m.set(99, R - 1, 'G'); // --- x102-124 冰上钻石阵 --- carpet(m, 102, R - 1, 23, '%'.length ? [] : []); // 冰面刺毯 ceil(m, 102, 124, R - 5); vgap(m, 106, R - 2); vgap(m, 111, R - 2); vgap(m, 116, R - 2); vgap(m, 121, R - 2); m.set(103, R - 1, 'G'); m.set(126, R - 1, 'G'); m.set(129, R - 1, 'X'); return m.out(); })(), }, // ============================================================ j5 关口 { id: 'j5', name: 'THE GAUNTLET', cn: '关口', type: 'jump', diff: 4, hint: '移动平台跨刺海,炮台点名,矮洞与钻石阵穿插。', width: 122, grid: (() => { const W = 122, H = 28, R = 24; const m = new Grid(W, H); m.border('#'); m.rect(1, R, W - 2, 1, '#'); m.set(3, R - 1, 'S'); // --- x5-22 热身刺毯(三道上下夹缝)--- carpet(m, 5, R - 1, 17); ceil(m, 5, 21, R - 6); vgap(m, 9, R - 2); vgap(m, 15, R - 2); vgap(m, 21, R - 2); m.set(7, R - 1, 'G'); // --- x23-49 移动平台跨海 --- for (let x = 23; x <= 49; x++) { m.set(x, R, '.'); m.set(x, R + 1, '^'); } m.set(50, R - 1, 'G'); // --- x51-72 矮洞 + 炮台 --- m.rect(51, R - 4, 22, 1, '#'); // 顶 row 20 carpet(m, 52, R - 1, 20, [0]); hgap(m, 57, R - 1); hgap(m, 64, R - 1); hgap(m, 70, R - 1); m.set(56, R - 5, 'O'); m.set(52, R - 1, 'G'); // --- x73-97 浮块跨刺海 + 交叉火力 --- spikeRun(m, 73, R - 1, 24, '^'); block(m, 76, R - 2, 2); block(m, 82, R - 4, 2); block(m, 88, R - 2, 2); block(m, 93, R - 3, 2); ceil(m, 75, 96, R - 9); // 浮块区压顶:高块上二段跳必死 m.set(79, R - 6, 'O'); m.set(91, R - 6, 'O'); m.set(95, R - 1, 'G'); // --- x98-118 钻石收尾 --- carpet(m, 98, R - 1, 20, [0, 1, 19]); ceil(m, 98, 117, R - 6); vgap(m, 101, R - 2); vgap(m, 106, R - 2); vgap(m, 111, R - 2); vgap(m, 116, R - 2); m.set(98, R - 1, 'G'); m.set(119, R - 1, 'G'); m.set(120, R - 1, 'X'); return m.out(); })(), movers: [ { x: 25, y: 22, w: 2, h: 1, path: [[25, 22], [35, 22]], speed: 1.6 }, { x: 39, y: 20, w: 2, h: 1, path: [[39, 20], [47, 20]], speed: 1.9 }, ], turrets: [ { dir: 'left', period: 70, speed: 2.8, offset: 0 }, { dir: 'left', period: 62, speed: 3.0, offset: 24 }, { dir: 'left', period: 66, speed: 2.7, offset: 40 }, ], }, // ============================================================ j6 针刺教堂 { id: 'j6', name: 'NEEDLE CATHEDRAL', cn: '针刺教堂', type: 'jump', diff: 5, hint: '三层殿堂:底层向右,竖井爬升,中层折返向左,再爬升,顶层冲刺。', width: 132, grid: (() => { const W = 132, H = 36; const m = new Grid(W, H); m.border('#'); // ============ L0 底层(地板 row 30)============ m.rect(1, 30, W - 2, 1, '#'); m.set(3, 29, 'S'); carpet(m, 5, 29, 116); ceil(m, 5, 120, 24); vgap(m, 18, 28); vgap(m, 46, 28); vgap(m, 74, 28); vgap(m, 102, 28); block(m, 32, 29, 2); block(m, 60, 29, 2); block(m, 88, 29, 2); block(m, 112, 29, 2); m.set(11, 29, 'G'); m.set(55, 29, 'G'); m.set(95, 29, 'G'); // ============ 右井 x122-129 → L1(左墙底部留 3 格入口)============ m.vline(122, 17, 26, '#'); m.vline(129, 16, 29, '#'); block(m, 124, 27, 2); block(m, 126, 24, 2); block(m, 124, 21, 2); block(m, 126, 18, 2); wall(m, 129, 26, 26, '<'); wall(m, 122, 23, 23, '>'); wall(m, 129, 20, 20, '<'); // ============ L1 中层(地板 row 16,向左折返,延伸到两侧井底)============ m.rect(1, 16, 122, 1, '#'); carpet(m, 9, 15, 112); ceil(m, 9, 118, 10); vgap(m, 108, 14); vgap(m, 82, 14); vgap(m, 56, 14); vgap(m, 30, 14); hgap(m, 95, 15); hgap(m, 43, 15); block(m, 69, 15, 2); block(m, 17, 15, 2); m.set(113, 15, 'G'); m.set(63, 15, 'G'); m.set(21, 15, 'G'); // ============ 左井 x2-7 → L2(右墙底部留 3 格入口,桥接块接 L2 地板边)============ m.vline(8, 9, 12, '#'); block(m, 4, 13, 2); block(m, 2, 10, 2); block(m, 4, 7, 2); block(m, 6, 7, 2); // 桥 wall(m, 8, 11, 11, '<'); wall(m, 2, 10, 10, '>'); // ============ L2 顶层(地板 row 8,向右到终点)============ m.rect(8, 8, 118, 1, '#'); carpet(m, 9, 7, 114); m.set(8, 7, '.'); m.set(9, 7, '.'); m.set(10, 7, '.'); m.set(11, 7, '.'); // 井口净空 ceil(m, 9, 122, 2); vgap(m, 24, 6); vgap(m, 60, 6); vgap(m, 96, 6); hgap(m, 36, 7); hgap(m, 84, 7); m.set(15, 7, 'G'); m.set(51, 7, 'G'); m.set(87, 7, 'G'); m.set(122, 7, 'X'); return m.out(); })(), }, // ============================================================ j7 天降刺 { id: 'j7', name: 'SKY SPIKES', cn: '天降刺', type: 'jump', diff: 4, hint: '之字爬塔,每层头顶悬着掉落刺。走近就掉。别停。', width: 72, grid: (() => { const W = 72, H = 52; const m = new Grid(W, H); m.border('#'); m.rect(1, 48, W - 2, 1, '#'); m.set(3, 47, 'S'); // 6 层之字平台:每层刺毯 + 钻石 + 掉落刺 const tiers = [ { y: 44, x0: 4, x1: 30 }, { y: 38, x0: 34, x1: 62 }, { y: 32, x0: 6, x1: 34 }, { y: 26, x0: 38, x1: 64 }, { y: 20, x0: 8, x1: 36 }, { y: 14, x0: 40, x1: 64 }, ]; for (const t of tiers) { m.rect(t.x0, t.y, t.x1 - t.x0 + 1, 1, '#'); // 3/4 格交替刺毯;两端各留 2 格净空作为上一层跃入 / 下一层起跳的落脚点 const n = t.x1 - t.x0 + 1; carpet(m, t.x0, t.y - 1, n, [0, 1, n - 2, n - 1]); for (let x = t.x0 + 5; x <= t.x1 - 3; x += 7) m.set(x, t.y - 8, 'D'); ceil(m, t.x0 + 2, t.x1 - 2, t.y - 5); // 压顶垂刺:层内二段跳必死 vgap(m, Math.floor((t.x0 + t.x1) / 2), t.y - 2); } // 层间连接块(升 2 格,落点对准缺口) block(m, 32, 46, 2); block(m, 32, 42, 2); block(m, 34, 40, 2); block(m, 32, 36, 2); block(m, 30, 34, 2); block(m, 36, 30, 2); block(m, 38, 28, 2); block(m, 36, 24, 2); block(m, 34, 22, 2); block(m, 38, 18, 2); block(m, 40, 16, 2); // 存档(各层缺口上) m.set(7, 43, 'G'); m.set(37, 37, 'G'); m.set(9, 31, 'G'); m.set(41, 25, 'G'); m.set(11, 19, 'G'); m.set(43, 13, 'G'); m.set(60, 13, 'X'); return m.out(); })(), }, // ============================================================ j8 三重威胁 { id: 'j8', name: 'TRIPLE THREAT', cn: '三重威胁', type: 'jump', diff: 4, hint: '冰面滑行、塌陷浮桥、单向台攀爬三连考,中间不许喘气。', width: 130, grid: (() => { const W = 130, H = 26, R = 22; const m = new Grid(W, H); m.border('#'); m.rect(1, R, W - 2, 1, '#'); m.set(3, R - 1, 'S'); // --- x1-34 冰面段 --- m.rect(1, R, 36, 1, '%'); for (const [a, b] of [[7, 9], [13, 15], [19, 21], [26, 29]]) for (let x = a; x <= b; x++) { m.set(x, R, '.'); m.set(x, R + 1, '^'); } vgap(m, 11, R - 2); vgap(m, 17, R - 2); vgap(m, 24, R - 2); vgap(m, 30, R - 2); m.set(11, R - 1, 'G'); m.set(32, R - 1, 'G'); // --- x38-74 塌陷浮桥(桥下刺海)--- for (let x = 38; x <= 74; x++) { m.set(x, R, '.'); m.set(x, R + 1, '^'); } for (let x = 38; x <= 74; x++) m.set(x, R - 3, 'V'); m.set(46, R - 4, '^'); m.set(50, R - 4, '^'); m.set(54, R - 4, '^'); m.set(58, R - 4, '^'); m.set(62, R - 4, '^'); m.set(66, R - 4, '^'); m.set(70, R - 4, '^'); ceil(m, 40, 72, R - 9); // 垂刺限高 m.set(51, R - 4, 'G'); // --- x76-100 单向台攀爬 --- for (let x = 76; x <= 99; x++) { m.set(x, R, '.'); m.set(x, R + 1, '^'); } m.set(78, R - 2, '-'); m.set(79, R - 2, '-'); m.set(83, R - 4, '-'); m.set(84, R - 4, '-'); m.set(88, R - 6, '-'); m.set(89, R - 6, '-'); m.set(93, R - 4, '-'); m.set(94, R - 4, '-'); m.set(97, R - 2, '-'); m.set(98, R - 2, '-'); vgap(m, 86, R - 8); vgap(m, 93, R - 6); m.set(101, R - 1, 'G'); // --- x102-126 钻石收尾 --- carpet(m, 102, R - 1, 24, [0, 1, 20, 21]); ceil(m, 102, 125, R - 5); vgap(m, 105, R - 2); vgap(m, 110, R - 2); vgap(m, 115, R - 2); vgap(m, 120, R - 2); m.set(102, R - 1, 'G'); m.set(126, R - 1, 'X'); return m.out(); })(), }, // ============================================================ j9 樱花 { id: 'j9', name: 'CHERRY BLOSSOM', cn: '樱花', type: 'jump', diff: 5, hint: '双层结构收 3 个苹果:钻石缝中央一个,矮洞里一个,中层对刺门后一个。', width: 128, grid: (() => { const W = 128, H = 34; const m = new Grid(W, H); m.border('#'); // ============ L0 下层(地板 row 28)============ m.rect(1, 28, W - 2, 1, '#'); m.set(3, 27, 'S'); carpet(m, 5, 27, 116); ceil(m, 5, 120, 22); vgap(m, 14, 26); vgap(m, 38, 26); vgap(m, 86, 26); vgap(m, 110, 26); block(m, 26, 27, 2); block(m, 50, 27, 2); block(m, 74, 27, 2); block(m, 98, 27, 2); m.set(11, 27, 'G'); m.set(55, 27, 'G'); m.set(95, 27, 'G'); // 井口前净空(否则刺毯把竖井入口封死) m.set(117, 27, '.'); m.set(118, 27, '.'); m.set(119, 27, '.'); m.set(120, 27, '.'); // 苹果 1:钻石缝中央 m.set(62, 26, 'F'); // ============ L0 中段矮洞(顶 row 24,3 格高;撞头跳射程≈3 格,洞内缺口加密到 3)============ m.rect(60, 24, 16, 1, '#'); [63, 66, 69, 72, 75].forEach(x => m.set(x, 27, '.')); // 苹果 2:矮洞里(跳跃途中拾取) m.set(66, 26, 'F'); // ============ 右井 x120-126 → L1(左墙底部留 3 格入口)============ m.vline(119, 15, 24, '#'); m.vline(126, 14, 27, '#'); block(m, 121, 25, 2); block(m, 124, 22, 2); block(m, 121, 19, 2); block(m, 124, 16, 2); wall(m, 126, 24, 24, '<'); wall(m, 119, 21, 21, '>'); wall(m, 126, 18, 18, '<'); // ============ L1 上层(地板 row 14,向左折返,延伸到井底)============ m.rect(2, 14, 118, 1, '#'); carpet(m, 9, 13, 108); ceil(m, 9, 116, 8); hgap(m, 100, 13); hgap(m, 68, 13); hgap(m, 36, 13); vgap(m, 84, 12); vgap(m, 52, 12); vgap(m, 20, 12); m.set(105, 13, 'G'); m.set(59, 13, 'G'); // 苹果 3:对刺门后 m.set(44, 12, 'F'); // ============ 终点(上层左端)============ m.set(10, 13, 'X'); return m.out(); })(), }, // ============================================================ j10 毕业 { id: 'j10', name: 'FINAL NEEDLE', cn: '毕业针刺', type: 'jump', diff: 5, hint: '四层大考场:刺毯长廊 → 冰面折返 → 矮洞 → 高空钢丝。全程无尿点。', width: 150, grid: (() => { const W = 150, H = 44; const m = new Grid(W, H); m.border('#'); // ============ L0 刺毯长廊(地板 row 38,向右)============ m.rect(1, 38, W - 2, 1, '#'); m.set(3, 37, 'S'); carpet(m, 5, 37, 134); ceil(m, 5, 138, 32); vgap(m, 20, 36); vgap(m, 48, 36); vgap(m, 76, 36); vgap(m, 104, 36); vgap(m, 128, 36); block(m, 34, 37, 2); block(m, 62, 37, 2); block(m, 90, 37, 2); block(m, 118, 37, 2); m.set(11, 37, 'G'); m.set(59, 37, 'G'); m.set(107, 37, 'G'); // ============ 右井 A x140-147 → L1(左墙底部留 3 格入口)============ m.vline(139, 29, 34, '#'); m.vline(147, 28, 37, '#'); block(m, 141, 35, 2); block(m, 144, 32, 2); block(m, 141, 29, 2); block(m, 144, 26, 2); wall(m, 147, 34, 34, '<'); wall(m, 139, 31, 31, '>'); // ============ L1 冰面层(地板 row 28,向左,延伸到井底)============ m.rect(2, 28, 138, 1, '%'); carpet(m, 11, 27, 126); m.set(136, 27, '.'); m.set(137, 27, '.'); m.set(138, 27, '.'); // 井 A 出口落点净空 ceil(m, 11, 136, 22); vgap(m, 116, 26); vgap(m, 88, 26); vgap(m, 60, 26); vgap(m, 32, 26); block(m, 102, 27, 2); block(m, 74, 27, 2); block(m, 46, 27, 2); m.set(121, 27, 'G'); m.set(69, 27, 'G'); m.set(23, 27, 'G'); // ============ 左井 B x2-8 → L2(右墙底部留 3 格入口)============ m.vline(8, 17, 24, '#'); block(m, 4, 25, 2); block(m, 2, 22, 2); block(m, 4, 19, 2); block(m, 5, 17, 2); wall(m, 8, 21, 21, '<'); wall(m, 2, 20, 20, '>'); wall(m, 8, 18, 18, '<'); // ============ L2 矮洞层(地板 row 16,向右,延伸到井 C 底)============ m.rect(8, 16, 138, 1, '#'); m.rect(10, 12, 128, 1, '#'); // 矮洞顶(3 格高洞) carpet(m, 10, 15, 128); m.set(8, 15, '.'); m.set(9, 15, '.'); // 井 B 出口净空 hgap(m, 72, 15); m.set(19, 15, 'G'); m.set(67, 15, 'G'); m.set(115, 15, 'G'); // ============ 右井 C x140-147 → L3(左墙底部留 3 格入口,桥接块接 L3)============ m.vline(139, 9, 12, '#'); m.vline(147, 8, 15, '#'); block(m, 141, 13, 2); block(m, 144, 10, 2); block(m, 141, 7, 2); block(m, 137, 7, 4); // 桥:向左落到 L3 基座 wall(m, 147, 12, 12, '<'); wall(m, 139, 10, 10, '>'); // ============ L3 高空钢丝(基座 row 8 + 刺毯 row 7,开放高空,向左到终点)============ m.rect(8, 8, 130, 1, '#'); spikeRun(m, 9, 7, 128, '^'); // 刺毯基底 for (let x = 133; x <= 137; x++) m.set(x, 7, '.'); // 井口落脚区 // 钢丝柱:间距 3~6 不规则,柱顶 row 5~7 错落 const wires = []; const steps = [4, 5, 3, 6, 4, 3, 5, 4, 6, 3, 5, 4, 4, 6, 3, 5, 4, 6, 4, 3, 5, 4, 6, 3, 5, 4, 4, 3]; let wx = 132; wires.push(wx); for (const s of steps) { wx -= s; if (wx < 14) break; wires.push(wx); } wires.forEach((x, i) => m.vline(x, [6, 5, 7, 6, 7, 5][i % 6], 7, '#')); // 存档放在两根钢丝顶上 const g1 = wires[6], g2 = wires[Math.floor(wires.length / 2) + 4]; const topOf = i => [6, 5, 7, 6, 7, 5][i % 6]; m.set(g1, topOf(6) - 1, 'G'); m.set(g2, topOf(wires.indexOf(g2)) - 1, 'G'); m.rect(8, 7, 4, 1, '#'); // 终点台 m.set(9, 6, 'X'); return m.out(); })(), }, ]; export default JUMP_LEVELS;