纠正仓库内容为衍生项目,标明 campaign-200-r2 最新版
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
import fs from 'node:fs';import path from 'node:path';import crypto from 'node:crypto';import {fileURLToPath} from 'node:url';import {graph} from '../../tools/engine-template.mjs';
|
||||
const here=path.dirname(fileURLToPath(import.meta.url)),root=path.resolve(here,'../..');const plan=JSON.parse(fs.readFileSync(path.join(here,'demo-design.json'),'utf8'));const assertions=[];
|
||||
function check(name,condition){if(!condition)throw Error(name);assertions.push(name);}
|
||||
check('50条设计任务',plan.levels.length===50);check('ID不重复',new Set(plan.levels.map(l=>l.levelId)).size===50);check('关号连续',plan.levels.every((l,i)=>l.displayOrder===i+1));check('五章,每章十关',plan.chapters.length===5&&plan.chapters.every(c=>plan.levels.filter(l=>l.chapter===c.id).length===10));
|
||||
const expectedIds=[...plan.levels.map(l=>l.levelId)].sort().join();for(const [key,order]of Object.entries(plan.orders))check('关序'+key+'为同题库排列',[...order.levelIds].sort().join()===expectedIds);
|
||||
for(const l of plan.levels){check(l.designKey+'候选状态准确',l.status==='design-only'&&!l.geometryValidated&&!l.uniqueSolutionValidated&&!l.humanDifficultyCalibrated&&l.measuredFeatures===null);check(l.designKey+'项目规模',l.nodeCountTarget>=5&&l.nodeCountTarget<=20);check(l.designKey+'目标带',l.targetDifficultyBand[0]<=l.targetDifficulty&&l.targetDifficulty<=l.targetDifficultyBand[1]);check(l.designKey+'不叠双色奇偶',!(l.features.includes('alternation')&&l.features.includes('parity')));check(l.designKey+'通道仅单位方格',!l.features.includes('direction')||l.geometry==='square'&&!l.features.includes('big'));check(l.designKey+'奇偶避免天然方格',!l.features.includes('parity')||l.geometry!=='square');check(l.designKey+'教学与排除依据',Boolean(l.layoutIntent&&l.teachingGoal&&l.temptingRouteIntent&&l.rejectionReason));}
|
||||
for(let c=1;c<=5;c++){const chunk=plan.levels.filter(l=>l.chapter===c),peak=chunk[7].targetDifficulty;check('第'+c+'章第8关峰值',chunk.every(l=>l.targetDifficulty<=peak));check('第'+c+'章末两关回落',chunk[8].targetDifficulty<peak&&chunk[9].targetDifficulty<peak);}
|
||||
check('不给前50关用尽分值',Math.max(...plan.levels.map(l=>l.targetDifficulty))<80);
|
||||
const snapshot=[];for(const mode of ['direction','block-alternation','walls','rhythm-door','hex-alternation']){const pack=JSON.parse(fs.readFileSync(path.join(root,'modes',mode,'levels.json'),'utf8'));const designs=JSON.parse(fs.readFileSync(path.join(root,'modes',mode,'design.json'),'utf8'));for(let k=0;k<pack.levels.length;k++){const l=pack.levels[k],g=graph(l),paint=new Map();let bipartite=true;function bfs(start){const queue=[start];paint.set(start,0);for(let i=0;i<queue.length;i++)for(const j of g.adj[queue[i]]){if(!paint.has(j)){paint.set(j,1-paint.get(queue[i]));queue.push(j);}else if(paint.get(j)===paint.get(queue[i]))bipartite=false;}}for(let i=0;i<l.cells.length;i++)if(!paint.has(i))bfs(i);snapshot.push({reference:mode+'/'+l.id,n:l.cells.length,geometry:l.geometry,numericClues:l.cells.filter(c=>c.clue!==undefined).length,rawEdgeCount:g.adj.reduce((n,a)=>n+a.length,0)/2,rawDegreeThreePlusNodes:g.adj.filter(a=>a.length>=3).length,rawDegreeTwoRatio:g.adj.filter(a=>a.length===2).length/l.cells.length,rawGeometryBipartite:bipartite,basePathCount:designs[k].basePathCount,notes:'原始几何指标,不代表有效决策B、强制比例F或真人难度'});}}
|
||||
fs.writeFileSync(path.join(here,'project-snapshot.json'),JSON.stringify({existingLevels:snapshot.length,status:'只读结构快照,未重跑关卡发布校验',metrics:snapshot},null,2));const references=new Set(snapshot.map(s=>s.reference));check('所有原型参考存在',plan.levels.every(l=>l.sourceCandidates.every(id=>references.has(id))));
|
||||
const bytes=fs.readFileSync(plan.researchSource.path);check('报告版本一致',crypto.createHash('sha256').update(bytes).digest('hex')===plan.researchSource.sha256);
|
||||
const baseline=JSON.parse(fs.readFileSync(path.join(root,'reports','original-before.json'),'utf8').replace(/^\uFEFF/,''));const changed=baseline.filter(item=>!fs.existsSync(item.path)||crypto.createHash('sha256').update(fs.readFileSync(item.path)).digest('hex').toUpperCase()!==item.hash).map(item=>item.path);
|
||||
const directoryFiles=[];function walk(dir){for(const e of fs.readdirSync(dir,{withFileTypes:true})){if(e.isDirectory()&&['.git','node_modules'].includes(e.name))continue;const p=path.join(dir,e.name);if(e.isDirectory())walk(p);else if(e.isFile())directoryFiles.push(p);}}walk('G:\\项目\\NumberSwipe');const originalSet=new Set(baseline.map(x=>x.path)),added=directoryFiles.filter(f=>!originalSet.has(f));const knownResearchAdditions=['docs/一笔画竞品调研与关卡编排方案.md','docs/一笔画深度调研-制作与难度证据.md','docs/research/audit-level-structure.mjs','docs/research/level-structure-audit.json'].map(p=>path.join('G:\\项目\\NumberSwipe',p));check('历史原项目91文件内容不变;新增仅既有研究文件',changed.length===0&&added.every(p=>knownResearchAdditions.includes(p)));check('六道桥接样题计入50关',plan.pilotDesignKeys.length===6&&plan.pilotDesignKeys.every(k=>plan.levels.some(l=>l.designKey===k)));for(const r of plan.additionalResearchSources)check('补充研究版本一致 '+path.basename(r.path),crypto.createHash('sha256').update(fs.readFileSync(r.path)).digest('hex')===r.sha256);
|
||||
const summary={checkedAt:new Date().toISOString(),passed:true,designTasks:50,existingLevelsInspected:snapshot.length,checkedAssertions:assertions.length,originalProjectFilesChecked:baseline.length,originalProjectChanged:changed,originalProjectAddedSinceHistoricalBaseline:added,originalProjectWritesByThisPlanningTask:0,isolationNote:'相较旧清单已有4份研究文件新增;本任务只读原项目,写入design/demo-50。',assertions,scope:'仅设计表、曲线、规则组合与来源一致性检查;不代表50关可玩、唯一解或真人难度验收'};fs.writeFileSync(path.join(here,'plan-check.json'),JSON.stringify(summary,null,2));console.log(JSON.stringify({passed:true,tasks:50,checks:assertions.length,originalFiles:baseline.length,changed:changed.length,added:added.length}));
|
||||
Reference in New Issue
Block a user