将分层反馈强化版提升为正式 main,统一协作入口并移除外部构建路径

This commit is contained in:
toshiocn
2026-10-23 11:04:37 +08:00
parent 83e2e40269
commit a156e8b5c6
173 changed files with 1181 additions and 498 deletions
+10 -10
View File
@@ -9,7 +9,7 @@ const root = path.dirname(fileURLToPath(import.meta.url)), pack = JSON.parse(fs.
for (const file of manifest.files) {
const hash = p => crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex');
assert.equal(hash(path.join(root, 'src/upstream', file.name)), file.sha256);
assert.equal(hash(path.join(manifest.source, file.name)), file.sha256);
assert.equal(hash(path.resolve(root, manifest.source, file.name)), file.sha256);
}
const ordered = pack.playOrder.map(id => pack.levels.find(l => l.id === id));
assert.equal(ordered.length, 200);
@@ -35,7 +35,7 @@ function boot(storage = new Map(), width = 375, height = 812) {
const cell = id => { const s=api.snapshot(),[x,y]=s.centers[id];tap(x+s.boardRect.x,y+s.boardRect.y); };
const select = i => { if(api.buttons().some(b=>b.label==='返回游戏'))button('返回游戏'); if (api.snapshot().screen !== 'select')
button('选关'); const label = String(i + 1); let steps = 0; while (!api.buttons().some(b => b.label === label || b.label === label + ' ✓')) {
button(api.snapshot().selection.chapter>Math.floor(i/10)+1?'上一页':'下一页');
button(api.snapshot().selection.page>Math.floor(i/15)+1?'上一页':'下一页');
assert.ok(++steps < 25);
} button(api.buttons().some(b => b.label === label) ? label : label + ' ✓'); if (api.buttons().some(b => b.label === '返回游戏'))
button('返回游戏'); assert.equal(api.snapshot().level, ordered[i].id); };
@@ -96,7 +96,7 @@ const restored = boot(ui.storage, 320, 640);
assert.equal(restored.api.snapshot().level, ordered[199].id);
assert.equal(JSON.parse(ui.storage.get('variant:campaign-200-r2:v1')).length, 200);
restored.button('规则');assert.ok(restored.api.buttons().every(b=>b.y>=0&&b.y+b.h<=640));const smallBefore=restored.api.snapshot();restored.advance(5200);assert.deepEqual(restored.api.snapshot().path,smallBefore.path);restored.button('返回游戏');
restored.button('音效开');
restored.button('设置');restored.button('音效开');restored.button('完成');
const reopen = boot(ui.storage);
assert.equal(reopen.api.snapshot().soundEnabled, false);
// 在多种手机尺寸下验证通关后的真实按钮、绘制区域与点击跳转。
@@ -116,13 +116,13 @@ const narrow=boot(new Map(),320,568);
for(const l of ordered.filter(l=>l.tutorial)){narrow.select(ordered.indexOf(l));narrow.button('规则');let pages=0;do{assert.ok(narrow.api.buttons().every(b=>b.y>=0&&b.y+b.h<=568));const before=narrow.api.snapshot();narrow.advance(3900);const after=narrow.api.snapshot();for(const field of ['path','centers','doors','latchedDoors','records','lastSound'])assert.deepEqual(after[field],before[field],field);if(!narrow.api.buttons().some(b=>b.label==='下一段'&&b.enabled))break;narrow.button('下一段');assert.ok(++pages<30);}while(true);narrow.button('返回游戏');}
const idle=boot();if(idle.api.buttons().some(b=>b.label==='返回游戏'))idle.button('返回游戏');idle.button('选关');idle.advance(1000);assert.equal(idle.frames.size,0,'静态选关页不持续绘制');
assert.ok(Object.values(idle.api.snapshot().fonts).every(v=>v==='loaded'));
idle.button('设置');idle.button('减少动态:关');idle.button('完成');
assert.equal(idle.api.snapshot().reducedMotion,true);
idle.select(162);idle.cell(solve(ordered[162])[0][0]);idle.advance(1000);
assert.equal(idle.frames.size,0,'减少动态的思考阶段不持续绘制');
idle.button('指路');idle.advance(1000);assert.ok(idle.api.snapshot().hint);assert.equal(idle.frames.size,0,'静态指路仍保留信息但不循环绘制');
const reducedRestored=boot(idle.storage);assert.equal(reducedRestored.api.snapshot().reducedMotion,true);
const result = {startupGameplay:true,chapterSelection:true,theme:'bright-classroom',bundledFonts:true,reducedMotionPersisted:true,idleRenderingStops:true,segmentHints:true,playerFillUnchangedAfterHint:true,animatedLessons:10,previewStateIsolation:true,narrowTutorials:'320x568', source: manifest.source, version: pack.version, total: 200, passed: 200, sourceHashesMatch: true, uniqueSolution: true, simulatedWeChatTouch: true, undoRestartHint: true, storageRestore: true, foregroundLoop: true, nativeAudioPlaybackCalls: ui.played.length, plainLanguageRules: true, pagedRules: true, clearActionLayout: true, phoneSizesChecked: 4, rows };
idle.button('设置');idle.button('音乐:开');idle.button('完成');
assert.equal(idle.api.snapshot().music.enabled,false);
idle.select(162);idle.cell(solve(ordered[162])[0][0]);idle.advance(2000);
assert.equal(idle.frames.size,0,'停手思考时停止绘制');
idle.button('指路');idle.advance(1000);assert.ok(idle.api.snapshot().hint);assert.ok(idle.frames.size>0,'流动指路持续更新');
const reducedRestored=boot(idle.storage);assert.equal(reducedRestored.api.snapshot().music.enabled,false);
const result = {channel:'main',eventFeedback:true,backtrackCore:true,hapticsIndependent:true,selectionColumns:3,deviceValidation:{iPhone:'pending',Android:'pending'},startupGameplay:true,chapterSelection:true,theme:'bright-classroom',bundledFonts:true,musicPreferencePersisted:true,idleRenderingStops:true,segmentHints:true,playerFillUnchangedAfterHint:true,animatedLessons:10,previewStateIsolation:true,narrowTutorials:'320x568', source: manifest.source, version: pack.version, total: 200, passed: 200, sourceHashesMatch: true, uniqueSolution: true, simulatedWeChatTouch: true, undoRestartHint: true, storageRestore: true, foregroundLoop: true, nativeAudioPlaybackCalls: ui.played.length, plainLanguageRules: true, pagedRules: true, clearActionLayout: true, phoneSizesChecked: 4, rows };
fs.writeFileSync(path.join(root, 'validation.json'), JSON.stringify(result, null, 2));
console.log('PASS 200/200: r2源文件哈希一致、唯一解、微信发布包触摸通关、撤销/重开/指路、存档/音效设置恢复、前后台切换。');