Faces cut into loose piles collapse outward instead of draining column by column (t93)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// Real nozzle cuts into settled heaps, inline and through the real Node worker pool.
|
||||
const fs = require('fs');
|
||||
const {createHash} = require('crypto');
|
||||
const {load, suite, enableThreads, flatWorld} = require('./harness');
|
||||
const {run} = load(), {check, done} = suite();
|
||||
run(fs.readFileSync(require.resolve('./pile-cut.js'), 'utf8'));
|
||||
const hash = () => createHash('sha256').update(run('mat')).digest('hex');
|
||||
// The longer spill must check barriers even when its starting chunk has no cleats.
|
||||
flatWorld(run, 96, 160, 80);
|
||||
run(`for(let y=18;y<=31;y++)setCell(y*W+29,RSTONE,AMB[y],0);
|
||||
setCell(29*W+30,RSTONE,AMB[29],0);setCell(30*W+30,RSTONE,AMB[30],0);
|
||||
cleatMask[30*W+34]=1;cleatMask[34*W+33]=1;
|
||||
powder(30*W+30,30,30,RSTONE);`);
|
||||
check('face spill stops before cleats across chunk edges',run('mat[30*W+30]===EMPTY && mat[33*W+33]===RSTONE && !cleatChunks[0]'));
|
||||
(async () => {
|
||||
const expected = new Map();
|
||||
for (const workers of [0, 2]) for (const mixed of [false, true]) for (const near of [false, true]) {
|
||||
run(`pileCutWorld();pileCutSetup(160,${mixed});bot.x=700;bot.y=100;`);
|
||||
const stop = workers ? await enableThreads(run, workers) : null;
|
||||
try {
|
||||
run('for(let k=0;k<600;k++)simTick();');
|
||||
const settled = hash();
|
||||
run('awake.fill(3);for(let k=0;k<60;k++)simTick();');
|
||||
check('uncut heap is settled', hash() === settled);
|
||||
run(`for(let k=0;k<70;k++){pileCutStroke(160);simTick();}bot.x=${near ? 110 : 700};bot.y=170;`);
|
||||
const before = run('pileCutProfile(160)');
|
||||
check('vacuum removes grains without losing them', run('bagTotal') > 500 && before.grains + run('bagTotal') === 3600, JSON.stringify(before));
|
||||
run('for(let k=0;k<180;k++)simTick();');
|
||||
const after = run('pileCutProfile(160)'), label = `${mixed ? 'mixed' : 'stone'}, ${workers} workers, bot ${near ? 'near' : 'far'}`;
|
||||
check(`vacuum face slumps within 180 ticks (${label})`, after.cliff <= 2, `before ${before.cliff}, after ${after.cliff}`);
|
||||
if (workers) check('helpers actually processed chunks', run('simPool.activeMax') > 0);
|
||||
const key = `${mixed}/${near}`;
|
||||
if (!workers) expected.set(key, hash());
|
||||
else check(`vacuum collapse matches inline bytes (${label})`, hash() === expected.get(key));
|
||||
run('for(let k=0;k<1200;k++){awake.fill(3);simTick();}');
|
||||
const resting = hash();
|
||||
run('for(let k=0;k<600;k++){awake.fill(3);simTick();}for(let k=0;k<3;k++)simTick();');
|
||||
check(`settled cut heap stays put and sleeps (${label})`, hash() === resting && run('awake.every(v=>!v)'));
|
||||
} finally { if (stop) await stop(); }
|
||||
}
|
||||
let wideExpected;
|
||||
for (const workers of [0, 2]) {
|
||||
flatWorld(run, 768, 600, 224);
|
||||
run('bot.x=740;bot.y=100;for(let y=104;y<224;y++)for(let x=256;x<576;x++)setCell(y*W+x,RSTONE,AMB[y],0);');
|
||||
const stop = workers ? await enableThreads(run, workers) : null;
|
||||
try {
|
||||
run('for(let k=0;k<600;k++)simTick();');
|
||||
const result = run(`(()=>{let cliff=0,previous=0,grains=0;
|
||||
for(let x=0;x<W;x++){let y=0;while(y<224&&mat[y*W+x]!==RSTONE)y++;
|
||||
const h=224-y;cliff=Math.max(cliff,Math.abs(h-previous));previous=h;
|
||||
for(;y<224;y++)if(mat[y*W+x]===RSTONE)grains++;}
|
||||
return {cliff,grains};})()`);
|
||||
check(`a broad 120-grain wall also releases (${workers} workers)`, result.cliff<=2 && result.grains===38400, JSON.stringify(result));
|
||||
if (!workers) wideExpected=hash();
|
||||
else check('broad wall release matches inline bytes',hash()===wideExpected);
|
||||
} finally { if (stop) await stop(); }
|
||||
}
|
||||
done();
|
||||
})().catch(e => { console.error(e); process.exitCode = 1; });
|
||||
Reference in New Issue
Block a user