97 lines
8.7 KiB
JavaScript
97 lines
8.7 KiB
JavaScript
import { readFile, writeFile } from 'node:fs/promises';
|
||
|
||
const root = new URL('../', import.meta.url);
|
||
const read = async path => JSON.parse(await readFile(new URL(path, root), 'utf8'));
|
||
const [levels, manifest, report, validation] = await Promise.all(['levels/v0.5.json', 'levels/v0.5-recipes.json', 'levels/v0.5-analysis.json', 'levels/v0.5-validation.json'].map(read));
|
||
if (levels.length !== 1000 || validation.result !== 'passed' || validation.pipelineHash !== manifest.pipelineHash) throw new Error('Run levels:v05:verify against this exact edition first');
|
||
const rows = report.levels, sum = report.summary;
|
||
const count = values => values.reduce((result, value) => ((result[value] = (result[value] || 0) + 1), result), {});
|
||
const primary = (row, policy) => policy.paths.some(path => path.id === row.reward.heroId && path.bends >= manifest.recipes[row.level - 1].slot.minHeroBends);
|
||
const minLong = Math.min(...rows.map(row => row.policies.filter(p => p.longPaths > 0).length));
|
||
const minPrimary = Math.min(...rows.map(row => row.policies.filter(p => primary(row, p)).length));
|
||
const families = { petals: '花瓣', orbits: '环绕', spiral: '螺旋', switchback: '回折', weave: '编织', crossing: '双叶交叉' };
|
||
const kinds = { tour: '长路巡游', gate: '清挡放行', contrast: '轻巧反差', turn: '旋转换路', stages: '分段释放' };
|
||
const chapters = manifest.campaign.chapters.map((name, i) => {
|
||
const group = rows.slice(i * 50, i * 50 + 50), tiers = count(group.map(row => row.difficulty.tier));
|
||
return `| ${i + 1} · ${name} | ${i * 50 + 1}–${i * 50 + 50} | ${Array.from({ length: 5 }, (_, tier) => tiers[tier + 1] || 0).join(' / ')} | ${Math.min(...group.map(r => r.tiles))}–${Math.max(...group.map(r => r.tiles))} | ${group.filter(r => r.difficulty.requiredRotations > 0).length} | [总览](v0.5-review/contact-${String(i + 1).padStart(2, '0')}.png) |`;
|
||
});
|
||
const policies = Object.entries(sum.byPolicy).map(([name, value]) => `| ${name} | ${value.runs} | ${value.won} | ${value.longRoute} |`);
|
||
const text = `# v0.5「千段轨迹」1000 关制作报告
|
||
|
||
日期:2026-09-12。首版已经冻结 1000 个可玩布局,20 章 × 50 关,直接接入原游戏运行时。旧版布局与独立进度保留。当前交付是经过规则、策略和静态画面检查的试玩版本;没有把自动通过当作已证明千关长期体验优良。
|
||
|
||
- [从第 1 关开始](http://localhost:4173/?campaign=v0.5&level=1)
|
||
- [第 1000 关](http://localhost:4173/?campaign=v0.5&level=1000)
|
||
- [制作审核页](http://localhost:4173/labs/campaign-review/index.html)
|
||
|
||
## 实际产出与验收
|
||
|
||
| 项目 | 本批结果 |
|
||
| --- | ---: |
|
||
| 冻结布局 / 独立求解成功 | ${levels.length} / ${validation.independentlySolved} |
|
||
| 忽略颜色、名称并整体旋转/镜像归一后的不同布局 | ${validation.uniqueLayouts} |
|
||
| 完整回放(作者解 + 最少旋转解 + 20 种策略) | ${validation.completeReplays} |
|
||
| 通过回放的成功操作 | ${validation.successfulActions} |
|
||
| 需要旋转 / 不需要旋转 | ${sum.rotationRequired} / ${levels.length - sum.rotationRequired} |
|
||
| 最少旋转数的最高值 | ${sum.maxRequiredRotations} |
|
||
| 最少旋转解中有长路的关卡 | ${sum.longRouteLevels} |
|
||
| 最少旋转解中单次最长格步骤 / 最多转弯 | ${sum.longestSteps} / ${sum.longestBends} |
|
||
| 每关 20 策略中出现长路的最低次数 | ${minLong} |
|
||
| 每关 20 策略中出现指定主长路的最低次数 | ${minPrimary} |
|
||
|
||
长路的统计带是至少 6 次转弯;主目标还须满足该关制作卡的最低转弯数。格步骤允许一条路经过同一格的不同轨道,不等于不同格子的数量。以上是本引擎模型中的观察量,不是玩家通关率、观看率或平均时长。
|
||
|
||
## 形态、体验和难度
|
||
|
||
| 路线家族 | 关数 | 体验类型 | 关数 |
|
||
| --- | ---: | --- | ---: |
|
||
${Object.entries(families).map(([id, name], i) => { const k = Object.keys(kinds)[i]; return `| ${name} | ${sum.families[id] || 0} | ${k ? kinds[k] : '合计'} | ${k ? sum.experiences[k] || 0 : 1000} |`; }).join('\n')}
|
||
|
||
这六类是可变开口、可变规模和布子的路线家族,不是 1000 种独立美术外形。花瓣与编织使用棋子真正可以行驶的轨道配对。作者主棋子走过的配对中,属于强调造型的最低比例为 ${(sum.minHeroShapeRatio * 100).toFixed(1)}%;完整作者清盘覆盖全盘强调配对的最低比例为 ${(sum.minShapeUsage * 100).toFixed(1)}%。两个分母不同:主路确实属于造型,不代表每关会把整朵花的所有路线走遍。
|
||
|
||
结构难度 D1–D5 的实际数量为 ${Array.from({ length: 5 }, (_, i) => sum.difficultyTiers['D' + (i + 1)] || 0).join(' / ')}。分数使用必要旋转、放行深度、开局可走比例和扫掠阻挡,不加入长路转弯数;全部标记为未经玩家校准的结构预估。后期继续有直接巡游和小盘,不把关号、盘面尺寸或棋子数直接等同于难度。
|
||
|
||
| 章节 | 关号 | D1 / D2 / D3 / D4 / D5 | 棋子数范围 | 需旋转关数 | 画面 |
|
||
| --- | --- | --- | --- | ---: | --- |
|
||
${chapters.join('\n')}
|
||
|
||
## 制作逻辑与质量修正
|
||
|
||
先构造有形态的开放路线,再逆向布子并保存完整构造解。换路关与反差关包含旋转前互相阻挡、旋转后可放行的核心棋子;分段关使用经正式碰撞与求解器验证的两次换路锁组。每个槽位在同一家族和体验内比较合格候选,避免只追求一个总分。
|
||
|
||
每个清挡关的指定短路门在开局即可移走,移走后主棋子立刻获得长路;作者回放从这个关键动作开始。巡游关开局可连续点选。反差关主棋子朝内,旋转一次即可走上长路;分段关的最少解也必须有至少两次旋转。
|
||
|
||
独立审核曾发现旧候选中“另一枚长路替主目标过检”、关键长路过晚及随机探索大量绕过的问题。本批增加了指定主棋子的单独门槛:核心六策略至少四条走到主长路,20 条中至少 16 条有长路、至少 10 条走到主长路;清挡与反差另查实际兑现的放行事件。这个筛选阈值是制作约束,不是研究证明的最优比例。
|
||
|
||
视觉审核还退回了过于相似的 849/850 连排:849 改为中盘编织巡游,850 保留为章末重瓣分段释放。小盘布子受到实际容量限制,避免通过堆积棋子延长关卡。
|
||
|
||
## 操作顺序的证据边界
|
||
|
||
四种“先清所有可出棋子再转”的常规策略可能得到相同统计,不能视作四份独立玩家证据。表中每行只是一个确定的策略。14 条额外随机探索与核心策略分别记录;额外的未参与筛选种子由独立质量审核报告说明。
|
||
|
||
| 策略 | 回放数 | 清盘数 | 出现长路数 |
|
||
| --- | ---: | ---: | ---: |
|
||
${policies.join('\n')}
|
||
|
||
## 画面、浏览器与尚未验证的范围
|
||
|
||
- [前 500 关静态审阅](v0.5-visual-audit-early.md)、[后 500 关静态审阅](v0.5-visual-audit-late.md):20 张逐章联系表的全局目检,不冒充 1000 次手玩。
|
||
- [浏览器记录](v0.5-browser-review.md):快速连点、清挡即发、反差、分段解、第 1000 关结算、选关/版本/缩放的实际样本与尺寸。
|
||
- [独立质量审核](v0.5-quality-audit.md):全量复查、主奖励出现时机、未参与筛选的策略与后续复审项。
|
||
- \`levels/v0.5-reviews.json\` 单独保存 AI 辅助静态审阅与浏览器样本状态;布局分析中的 \`visual: pending\` 是生成时快照,审核页会并列显示后续记录。
|
||
|
||
客户端读取冻结关卡,不在进入每关时实时生成。当前实现按章显示 50 项,但关卡模块仍一次载入全部数据;本地加载验证不等同于移动网络性能验证。真人新手/熟练玩家的连续游玩、疲劳、图案辨识度及留存尚未测量。原生 Cocos/Android/iOS 运行与实机触控没有在本轮验收。
|
||
|
||
## 文件与复现
|
||
|
||
布局全集:\`levels/v0.5.json\`;分章:\`levels/v0.5/chapter-01.json\` 至 \`chapter-20.json\`;浏览器模块:\`src/levels-v05.js\`。逐关配方在 \`levels/v0.5-recipes.json\`,策略与实际路径在 \`levels/v0.5-analysis.json\`,本批独立验证在 \`levels/v0.5-validation.json\`。
|
||
|
||
流水线 SHA-256:\`${manifest.pipelineHash}\`。
|
||
|
||
\`npm run levels:v05\` 离线重新生产;\`npm run levels:v05:verify\` 重求解并回放冻结数据;\`node scripts/write-production-report.mjs\` 只对已通过对应哈希验证的数据更新本报告。源码指纹改变时不允许混用旧检查点。
|
||
|
||
方法与最初假设见[千关制作方案](1000-level-production-plan.md)、[设计准则](level-design-principles-v2.md)和[论文与竞品知识库](level-design-knowledge/README.md)。
|
||
`;
|
||
await writeFile(new URL('docs/v0.5-production-report.md', root), text);
|
||
console.log('Wrote docs/v0.5-production-report.md from verified frozen data.');
|