// t45: finite carrying bed, local sustained jams, recovery, filters, screws and bars. const fs=require('fs'); const {load,flatWorld,suite,ticks}=require('./harness'); const {run}=load(), {check,done}=suite(); function fresh(){flatWorld(run,256,224,208);run('RS=7;AMB.fill(20);temp.fill(20);weather.next=1e15;nextPowerBuild=0;for(const k of Object.keys(stats))stats[k]=0;');} fresh(); run('placeBlock(BP_BELT,1,12,32,true);for(let l=1;l<=8;l++)setCell((128-l)*W+49,SAND,20,0);carryColumn(127*W+49,1,null);'); check('exactly four grains ride; the upper heap stays loose',run('Array.from({length:8},(_,k)=>mat[(127-k)*W+(k<4?50:49)]===SAND).every(Boolean)')); check('stall tracking exists',run('typeof transportStalled==="function"')); if(run('typeof transportStalled!=="function"')) {done();process.exit();} for(const code of ['BP_BELT','BP_FILTER','BP_SCREW']) { fresh(); run(`for(let bx=12;bx<20;bx++)placeBlock(${code},${code==='BP_FILTER'?128:1},bx,32,true,{m:[],inv:0}); for(let y=120;y<132;y++)for(let x=48;x<80;x++)if(mat[y*W+x]===EMPTY)setCell(y*W+x,SAND,20,0); for(let y=110;y<136;y++)setCell(y*W+80,STONE,20,0); placeBlock(BP_BELT,1,30,32,true); for(let bx=19;bx<=30;bx++)placeBlock(BP_SHAFT,0,bx,34,true); placeBlock(BP_SHAFT,0,19,33,true);placeBlock(BP_SHAFT,0,30,33,true);`); ticks(run,10); check(`${code}: a brief wait is not a stall`,run('!transportStalled(32*BW+19)')); ticks(run,240); check(`${code}: loaded blocked tail and upstream run warn`,run('transportStalled(32*BW+19)&&transportStalled(32*BW+15)')); check(`${code}: an unrelated empty belt stays clear (same power net for belts/screws)`,run('!transportStalled(32*BW+30)') && (code==='BP_FILTER' || run('netId[128*W+60]===netId[128*W+120]'))); const clock=run('transportClock(32*BW+19)');ticks(run,20); check(`${code}: animation clock freezes`,run('transportClock(32*BW+19)')===clock); run('for(let y=110;y<136;y++)setCell(y*W+80,EMPTY,20,0);');ticks(run,30); check(`${code}: clearing the blockage resumes motion`,run('!transportStalled(32*BW+19) && transportClock(32*BW+19)')>clock); } fresh();run('for(let bx=12;bx<40;bx++)placeBlock(BP_BELT,1,bx,32,true);spawnBar(BARCU,48,126,0,0);'); check('a steadily moving bar never reports a stall between whole-grain steps',run(`(()=>{for(let k=0;k<120;k++){simTick();if([...transportState.keys()].some(transportStalled))return false;}return ents[0].ix>90;})()`)); fresh();run('placeBlock(BP_BELT,1,12,32,true);placeBlock(BP_WALL,RSTONE,13,31,true);spawnBar(BARCU,48,126,0,0);');ticks(run,100); check('a blocked bar also stalls its carrying belt',run('transportStalled(32*BW+12)')); fresh(); run(`for(let k=0;k<8;k++)placeBlock(BP_BELT_UP,1,16+k,40-k,true); for(let y=110;y<132;y++)for(let x=96;x<100;x++)setCell(y*W+x,STONE,20,0); for(let y=110;y<166;y++)for(let x=56;x<96;x++)if(!part[y*W+x]&&mat[y*W+x]===EMPTY)setCell(y*W+x,SAND,20,0);`); ticks(run,100); check('a blocked cleat stops its whole slope run',run('Array.from({length:8},(_,k)=>transportStalled((40-k)*BW+16+k)).every(Boolean)')); const phase=run('slopePhase[40*BW+16]'), slopeClock=run('transportClock(40*BW+16)');ticks(run,20); check('stalled cleats and stripe clocks stay still together',run('slopePhase[40*BW+16]')===phase && run('transportClock(40*BW+16)')===slopeClock); fresh(); run(`for(let k=0;k<8;k++)placeBlock(BP_FILTER_DOWN,128,16+k,24+k,true,{m:[],inv:0}); for(let y=100;y<140;y++)setCell(y*W+96,STONE,20,0); for(let x=64;x<96;x++){const by=24+(x>>2)-16,y=beltFaceY(BP_FILTER_DOWN,x>>2,by,x);for(let l=1;l<=4;l++)setCell((y-l)*W+x,SAND,20,0);}`); ticks(run,300); check('a jammed downhill screen warns on its slower nudge cadence',run('transportStalled(31*BW+23)')); fresh();run(fs.readFileSync(__dirname+'/fixtures/t45-loop.js','utf8'));ticks(run,1800); console.log('Overloaded loop: '+run('JSON.stringify({moved:stats.moved,grains:mat.reduce((n,m)=>n+(m===SAND||m===CUORE),0),flyers:flyers.length,stalled:[...transportState].filter(([b,s])=>s.age>=STALL_TICKS).length})')); check('overloaded loop conserves its 832 grains',run('mat.reduce((n,m)=>n+(m===SAND||m===CUORE),0)+flyers.length')===832); done();