Files
kidgo/tools/solve.mjs
T
2026-10-21 13:54:25 +08:00

38 lines
1.9 KiB
JavaScript

// 可达性求解器:验证每关终点 / 存档点 / 苹果能否到达
// DJ=0,12,24 收紧二段跳时机;REL=0 禁用短跳 —— 检验是否只有"某一帧"能过
import { setupGlobals, reach, makeTargets } from './lib-reach.mjs';
setupGlobals();
const { LEVELS } = await import('../js/levels/index.js');
const DJSET = (process.env.DJ || '0,6,12,18,24,30').split(',').map(Number);
const RELSET = (process.env.REL || '0,4,8,14').split(',').map(Number);
let fail = 0;
console.log(`=== 可达性求解 (DJ=${DJSET} REL=${RELSET}) ===`);
for (const d of LEVELS) {
if (d.type === 'boss') { console.log(` ${d.id.padEnd(3)} ${d.name.padEnd(17)} (BOSS 关跳过)`); continue; }
let r;
try {
const { Level } = await import('../js/level.js');
const L = new Level(d);
const targets = makeTargets(L);
r = reach(L, { DJSET, RELSET, targets });
r.targets = targets;
} catch (e) { console.log(` ✗ ${d.id} 求解异常: ${e.message}`); fail++; continue; }
if (r.err) { console.log(` ✗ ${d.id.padEnd(3)} ${d.name.padEnd(17)} ${r.err}`); fail++; continue; }
const goal = r.targets.find(t => t.type === 'goal');
const saves = r.targets.filter(t => t.type === 'save');
const apples = r.targets.filter(t => t.type === 'apple');
const okSave = saves.filter(s => s.hit).length;
const okApple = apples.filter(a => a.hit).length;
const badSave = saves.filter(s => !s.hit).map(s => `#${s.no ?? s.idx}`);
const flag = goal && goal.hit ? ' ' : '✗';
if (!goal || !goal.hit) fail++;
if (badSave.length) fail++;
console.log(` ${flag} ${d.id.padEnd(3)} ${d.name.padEnd(17)} 终点=${goal ? (goal.hit ? 'OK' : '不可达') : '无'} 存档=${okSave}/${saves.length}${badSave.length ? ' 缺:' + badSave.join(',') : ''}${apples.length ? ` 苹果=${okApple}/${apples.length}` : ''} (状态${r.states})`);
}
console.log(fail ? `\n❌ ${fail} 项不可达` : '\n✅ 所有关卡终点与存档点均可达');
process.exit(fail ? 1 : 0);