from pathlib import Path import hashlib,json root=Path(r'G:\项目\NumberSwipe-Variants');dest=root/'campaign-50' files=list((root/'modes').rglob('*'));baseline=[{'path':str(p),'sha256':hashlib.sha256(p.read_bytes()).hexdigest()} for p in files if p.is_file()] (dest/'reports/prototype-before.json').write_text(json.dumps(baseline,ensure_ascii=False,indent=2),encoding='utf-8') s=(root/'tools/engine-template.mjs').read_text(encoding='utf-8-sig') s=s.replace("level.mode.includes('alternation')", "(level.features||[]).includes('alternation')") s=s.replace(" for(const c of level.cells)if(c.direction)result.push", " for(const c of level.cells)if(c.parity)result.push({key:'parity:'+c.id,kind:'parity',cell:c.id,value:c.parity});\n for(const c of level.cells)if(c.direction)result.push") s=s.replace(" else if(r.kind==='direction'){", " else if(r.kind==='parity'){where=[r.cell];const p=positions.get(r.cell);fail=p!==undefined&&(p%2===1)!==(r.value==='odd');}\n else if(r.kind==='direction'){") s=s.replace("r.kind==='direction'?'进出方向不符'", "r.kind==='parity'?'该格步号奇偶不符':r.kind==='direction'?'进出方向不符'") s=s.replace(" const g=graph(level),n=g.cells.length;if(n<3", " const g=graph(level),n=g.cells.length;if(level.features?.includes('alternation')&&level.features?.includes('parity'))throw Error('不叠加双色与奇偶');if(level.features?.includes('direction')&&level.geometry!=='square')throw Error('通道仅适用单位方格');if(n<3") s=s.replace(" if(r.kind==='direction'&&!Object.keys", " if(r.kind==='parity'&&(!['odd','even'].includes(r.value)||g.cells[g.ids.get(r.cell)].clue!==undefined))throw Error('奇偶字段或同格数字冲突');\n if(r.kind==='direction'&&!Object.keys") (dest/'rules.mjs').write_text(s,encoding='utf-8') (dest/'package.json').write_text(json.dumps({'name':'numberswipe-demo50','private':True,'type':'module','engines':{'node':'>=22'},'scripts':{'generate':'node tools/generate.mjs','build':'node tools/build.mjs','validate':'node tools/validate.mjs','test':'node --test tests/*.test.mjs','check':'node --test tests/*.test.mjs && node tools/validate.mjs'}},indent=2),encoding='utf-8') print('Independent campaign rules created; '+str(len(baseline))+' prototype files hashed.')