Files
NumberSwipe_New/archive/revision-scripts/revision.py
T

43 lines
6.0 KiB
Python

from pathlib import Path
root=Path(r'G:\项目\NumberSwipe-Variants')
p=root/'tools/engine-template.mjs'
s=p.read_text(encoding='utf-8-sig')
s=s.replace(" for(let i=0;i<(level.gates||[]).length;i++)result.push", " for(let i=0;i<(level.walls||[]).length;i++)result.push({key:'wall:'+i,kind:'wall',edge:level.walls[i]});\n for(let i=0;i<(level.doors||[]).length;i++)result.push({key:'door:'+i,kind:'door',...level.doors[i]});\n for(let i=0;i<(level.gates||[]).length;i++)result.push")
a=s.index('export function directionAt(');b=s.index('export function violations(',a)
s=s[:a]+'''export function directionAt(level,path,k){
if(k===0||k===path.length-1)return null;
const [a,b,c]=[path[k-1],path[k],path[k+1]].map(id=>level.cells.find(x=>x.id===id));
const side=(x)=>x.x<b.x?'l':x.x>b.x?'r':x.y<b.y?'u':'d';
return [side(a),side(c)].sort().join('');
}
export function doorOpen(door,visitedCount){return Boolean(door.initialOpen)!==Boolean(visitedCount%2);}
export const directionNames={lr:'左右直行',du:'上下直行',ru:'上与右拐角',dr:'右与下拐角',dl:'下与左拐角',lu:'左与上拐角'};
export function edgeBlocked(level,path,a,b,{omit=null}={}){
for(let i=0;i<(level.walls||[]).length;i++)if(omit!=='wall:'+i&&level.walls[i].includes(a)&&level.walls[i].includes(b))return true;
for(let i=0;i<(level.doors||[]).length;i++)if(omit!=='door:'+i&&level.doors[i].edge.includes(a)&&level.doors[i].edge.includes(b)&&!doorOpen(level.doors[i],path.length))return true;
return false;
}
''' +s[b:]
s=s.replace(" else if(r.kind==='gate')for", " else if(r.kind==='wall'||r.kind==='door')for(let i=1;i<path.length;i++){if(r.edge.includes(path[i-1])&&r.edge.includes(path[i])&&(r.kind==='wall'||!doorOpen(r,i))){fail=true;where=r.edge;}}\n else if(r.kind==='gate')for")
s=s.replace("r.kind==='gate'?'开关尚未打开此门':'类别没有交替'", "r.kind==='wall'?'永久墙不能穿过':r.kind==='door'?'这一步门是关闭的':r.kind==='gate'?'开关尚未打开此门':'蓝橙颜色必须交替'")
s=s.replace(" const last=path.at(-1);if(!g.adj", " const last=path.at(-1);if(edgeBlocked(level,path,last,id))return false;if(!g.adj")
s=s.replace(" const adj=g.adj.map((a,i)=>a.filter(j=>!alternating||g.cells[i].category!==g.cells[j].category));", " const adj=g.adj.map((a,i)=>a.filter(j=>(!alternating||g.cells[i].category!==g.cells[j].category)&&!active.some(r=>r.kind==='wall'&&r.edge.includes(g.cells[i].id)&&r.edge.includes(g.cells[j].id))));")
s=s.replace("let blocked=false;for(const r of active)", "let blocked=edgeBlocked(level,path,g.cells[i].id,g.cells[j].id,{omit});for(const r of active)")
s=s.replace("!['straight','turn'].includes(r.value)", "!Object.keys(directionNames).includes(r.value)")
s=s.replace(" if(r.kind==='gate'&&", " if((r.kind==='wall'||r.kind==='door')&&(r.edge.length!==2||!g.adj[g.ids.get(r.edge[0])].includes(g.ids.get(r.edge[1]))))throw Error('墙或门不在共边');\n if(r.kind==='gate'&&")
s=s.replace(" const pairs=[];", " if((level.doors||[]).length>1)throw Error('步进门只允许一道门');\n const physicalEdges=[...(level.walls||[]),...(level.doors||[]).map(d=>d.edge)].map(e=>[...e].sort().join('|'));if(new Set(physicalEdges).size!==physicalEdges.length)throw Error('墙门共边重复');\n const pairs=[];")
p.write_text(s,encoding='utf-8')
p=root/'tools/generate.mjs';s=p.read_text(encoding='utf-8-sig')
a=s.index(" }else if(def.id==='direction'){");b=s.index(" }else if(def.id.includes('alternation'))",a)
s=s[:a]+''' }else if(def.id==='direction'){
const kinds=['lr','du','ru','dr','dl','lu'];const pool={};for(const kind of kinds)pool[kind]=[];
for(let i=1;i<n-1;i++)pool[directionAt(level,author,i)].push(author[i]);
let pattern=index===0?['lr']:index===1?['corner']:index===2?['du']:index===3?['corner','corner']:index<6?['lr','du','corner']:['lr','du','corner','corner'];
const selected=[];for(const requested of pattern){const available=requested==='corner'?kinds.slice(2).filter(k=>pool[k].length):[requested];if(!available.length)return null;const kind=pick(available);if(!pool[kind].length)return null;const id=pick(pool[kind]);pool[kind].splice(pool[kind].indexOf(id),1);level.cells.find(c=>c.id===id).direction=kind;selected.push(kind);}
if(index===3&&selected[0]===selected[1])return null;
''' +s[b:]
s=s.replace(" }else if(def.id.includes('alternation'))for(let i=0;i<n;i++)level.cells.find(c=>c.id===author[i]).category=i%2?'triangle':'circle';", " }else if(def.id.includes('alternation')){for(let i=0;i<n;i++)level.cells.find(c=>c.id===author[i]).category=i%2?'triangle':'circle';if(def.geometry==='hex'){const g=graph(level);let edges=[];for(let a=0;a<n;a++)for(const b of g.adj[a])if(a<b&&Math.abs(author.indexOf(g.cells[a].id)-author.indexOf(g.cells[b].id))!==1&&g.cells[a].category!==g.cells[b].category)edges.push([g.cells[a].id,g.cells[b].id]);const count=index<3?1:index<6?2:3;if(edges.length<count)return null;level.walls=shuffle(edges).slice(0,count);}}\n else if(def.id==='walls'){const g=graph(level);let edges=[];for(let a=0;a<n;a++)for(const b of g.adj[a])if(a<b&&Math.abs(author.indexOf(g.cells[a].id)-author.indexOf(g.cells[b].id))!==1)edges.push([g.cells[a].id,g.cells[b].id]);const count=index<2?1:index<4?2:index<6?3:4;if(edges.length<count)return null;level.walls=shuffle(edges).slice(0,count);}\n else if(def.id==='rhythm-door'){const eligible=[];for(let i=0;i<n-1;i+=2)if(index===0?i===0:index<4?i>=2:i>=Math.floor(n/3))eligible.push(i);if(!eligible.length)return null;const e=pick(eligible);level.doors=[{edge:[at(e),at(e+1)],initialOpen:false}];}")
s=s.replace("r.value==='straight'?'直行':'转弯'", "({lr:'左右直行',du:'上下直行',ru:'上与右',dr:'右与下',dl:'下与左',lu:'左与上'})[r.value]")
s=s.replace("if(r.kind==='gate')return", "if(r.kind==='wall')return `永久墙 ${r.edge.join('—')} 断开表面邻接,需绕行`;if(r.kind==='door'){const crossing=author.findIndex((id,i)=>i>0&&r.edge.includes(id)&&r.edge.includes(author[i-1]));return `第 ${crossing} 格后门开,从 ${author[crossing-1]} 走向 ${author[crossing]},落格后门关;空盘门关、起步也切换`;}if(r.kind==='gate')return")
p.write_text(s,encoding='utf-8')