// Shared allocation, checkerboard independence, and real worker-count determinism. const assert = require('assert'); const { load, flatWorld } = require('./harness'); const { run } = load(); flatWorld(run, 131, 129, 110); assert(run('[mat,temp,life,flags,stamp,part,mach,digp,noiseB,bgm,airS,netId,isPow,occ,awake,hot,hotLvl,renderDirty,powderArea,cleatMask,cleatChunks,roofDirty,blockP,blockV,slopePhase,fog,AMB,roofY].every(a=>a.buffer instanceof SharedArrayBuffer)')); console.log('PASS world arrays use shared memory'); const crypto = require('crypto'); const { enableThreads } = require('./harness'); flatWorld(run, 192, 96, 31); run(`setCell(30*W+32,WATER,20,0);setCell(31*W+130,EMPTY,20,0); tick++;tickStamp++;var draws=0,savedRnd=rnd;rnd=()=>{draws++;return .99}; var searchWork=inlineChunkWork();runChunks([1],0,searchWork);`); assert(run('searchWork.events.some(e=>e[1]==="liquid")'), 'fixture must defer a long search'); run('mergeChunkWork([searchWork]);rnd=savedRnd;'); assert.strictEqual(run('draws'),1,'resuming a liquid search must not reroll its movement chance'); assert.strictEqual(run('mat[30*W+40]'),run('WATER'),'the resumed search finds the distant drop'); console.log('PASS long liquid search resumes without rerolling movement'); function setup() { flatWorld(run, 387, 257, 214); run(`{RS=123;WS=456;resetWeather();weather.next=1e15;seen.fill(0);ledger={};EV.length=0;for(const k of Object.keys(stats))stats[k]=0; resetEconomy();nextPowerBuild=0;bot.x=185;bot.y=120; const random=mulberry32(99), materials=[SAND,COAL,WATER,MAGMA,MCU,SNOW,LWOOD,STEAM,SMOKE]; for(let y=40;y<210;y++)for(let x=8;x { let expected; for (const n of [0,1,2,8,8,2,1,0]) { setup(); const stop = n ? await enableThreads(run,n) : null; try { run('for(let k=0;k<320;k++)simTick();'); const actual=hash(); if(!expected)expected=actual; assert.strictEqual(actual,expected,`world and effects differ with ${n} workers`); console.log(`PASS identical world and side effects with ${n} workers (${actual.slice(0,16)})`); } finally { if(stop)await stop(); } } setup(); run('const forwardChunks=runChunks;runChunks=(chunks,pass,work)=>forwardChunks(chunks.slice().reverse(),pass,work);for(let k=0;k<320;k++)simTick();runChunks=forwardChunks;'); assert.strictEqual(hash(),expected,'chunk order within a colour must not matter'); console.log('PASS reversing chunks within every pass preserves all bytes and effects'); const {execFileSync}=require('child_process'); const fallback=execFileSync(process.execPath,['-e',` global.SharedArrayBuffer=undefined; const {load,flatWorld}=require(${JSON.stringify(require.resolve('./harness'))}); const {run}=load();flatWorld(run,64,64,50); if(!run('mat.buffer instanceof ArrayBuffer'))throw Error('fallback allocation'); run('setCell(20*W+20,SAND,20,0);for(let k=0;k<60;k++)simTick();'); process.stdout.write(JSON.stringify(run('Array.from(mat)'))); `],{encoding:'utf8'}); flatWorld(run,64,64,50); run('setCell(20*W+20,SAND,20,0);for(let k=0;k<60;k++)simTick();'); assert.strictEqual(JSON.stringify(run('Array.from(mat)')),fallback); console.log('PASS Node ArrayBuffer fallback matches shared inline movement'); console.log('ALL PASS'); })().catch(e=>{console.error(e);process.exitCode=1;});