import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';import vm from 'node:vm';import {solve,graph,canAppend,violations} from '../rules.mjs'; const pack=JSON.parse(fs.readFileSync(new URL('../levels.json',import.meta.url),'utf8')); function boot(width=340,storage=new Map(),height=420,withAudio=false){const map=new Map(),draws=[],downloads=[];class Element{constructor(id=''){this.id=id;this.children=[];this.handlers={};this.value='';this.style={};this.className='';this.textContent='';this.hidden=false;this.disabled=false;}replaceChildren(){this.children=[];}append(...e){this.children.push(...e);}addEventListener(k,f){this.handlers[k]=f;}setPointerCapture(){}getBoundingClientRect(){return {left:0,top:0,width,height};}click(){this.onclick?.();if(this.download)downloads.push(this.download);}} const get=id=>{if(!map.has(id))map.set(id,new Element(id));return map.get(id);};const ctx={setTransform(){},clearRect(){draws.length=0;},beginPath(){this.p=[];},moveTo(x,y){this.p.push([x,y]);},lineTo(x,y){this.p.push([x,y]);},quadraticCurveTo(cx,cy,x,y){this.p.push([x,y]);},closePath(){},fill(){draws.push({kind:'fill',colour:this.fillStyle,points:this.p});},stroke(){draws.push({kind:'stroke',colour:this.strokeStyle,points:this.p});},fillText(s,x,y){draws.push({kind:'text',s,x,y});},save(){},restore(){},translate(){},rotate(){},setLineDash(){}};const canvas=get('board');canvas.clientWidth=width;canvas.clientHeight=height;canvas.getContext=()=>ctx;get('screen-play').className='screen hidden';get('screen-select').className='screen';const window={devicePixelRatio:1,handlers:{},addEventListener(k,f){this.handlers[k]=f;}};if(withAudio){let clock=0;window.AudioContext=class{get currentTime(){return clock+=.25;}constructor(){this.state='running';this.destination={};}createOscillator(){return {frequency:{setValueAtTime(){}},connect(){},disconnect(){},start(){},stop(){}};}createGain(){return {gain:{setValueAtTime(){},linearRampToValueAtTime(){},exponentialRampToValueAtTime(){}},connect(){},disconnect(){}};}};}const html=fs.readFileSync(new URL('../index.html',import.meta.url),'utf8');const script=html.match(/