Loose walls slump to a natural slope instead of eroding layer by layer (t93)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 18:58:40 -04:00
co-authored by Claude Opus 5.5
parent dadf62a28d
commit 807217b22c
7 changed files with 146 additions and 3 deletions
+48
View File
@@ -0,0 +1,48 @@
// Tall loose faces release together; supported heaps stop moving, including when revisited.
const {load, suite, flatWorld} = require('./harness');
const {createHash} = require('node:crypto');
const {run} = load();
const {check, done} = suite();
function wall(material, offset = 0) {
flatWorld(run, 192, 600, 96);
run(`RS=123; worldSeed=7; bot.x=500; bot.y=40;
for(let y=56;y<96;y++)for(let x=${80+offset};x<${100+offset};x++)setCell(y*W+x,${material},20,0);`);
}
function motion(n, revisit = false) {
run(`for(let k=0;k<${n};k++) {
tick++;tickStamp=tickStamp%255+1;
if (${revisit}) awake.fill(3);
simMove();
for(let c=0;c<NCH;c++)if(awake[c])awake[c]--;
}`);
}
function profile() {
return run(`(()=>{const h=[];let n=0,top=96;
for(let x=0;x<W;x++){let y=0;while(y<96&&PH[mat[y*W+x]]!==PH_POWDER)y++;
h.push(96-y);top=Math.min(top,y);
for(;y<96;y++)if(PH[mat[y*W+x]]===PH_POWDER)n++;
}
let cliff=0;for(let x=1;x<W;x++)cliff=Math.max(cliff,Math.abs(h[x]-h[x-1]));
return {cliff,height:96-top,n};})()`);
}
const hash = () => createHash('sha256').update(run('mat')).digest('hex');
const rubble = '[RSTONE,CUORE,FEORE,LDIRT][(x+y)%4]';
let sandHeight;
for(const [name, material] of [['sand','SAND'],['mixed rubble',rubble],['rubble with clay',`(x+y)%5===0?LCLAY:${rubble}`],['clay','LCLAY']]) {
for(const offset of [0,17]) {
wall(material,offset);
const maxCliff = name==='clay' ? 3 : 2;
let slopedAt=0;
for(let k=1;k<=180;k++) {motion(1);if(profile().cliff<=maxCliff&&!slopedAt)slopedAt=k;}
const p=profile();
check(`${name} face slumps within 180 ticks (offset ${offset})`,slopedAt>0&&p.cliff<=maxCliff&&p.n===800,JSON.stringify({slopedAt,...p}));
motion(1200,true);
if(name==='sand'&&offset===0)sandHeight=profile().height;
if(name==='clay'&&offset===0)check('sticky clay holds a steeper settled heap than sand',profile().height>sandHeight,`sand ${sandHeight}, clay ${profile().height}`);
const settled=hash();
// Force visits so sleeping cannot hide continued creeping.
motion(600,true);motion(3);
check(`${name} settled heap stays put and sleeps (offset ${offset})`,hash()===settled&&run('awake.every(v=>v===0)')&&profile().n===800);
}
}
done();
+3
View File
@@ -26,6 +26,9 @@ function setup() {
const m=materials[(random()*materials.length)|0];
setCell(y*W+x,m,m===MAGMA?1450:m===MCU?1200:m===STEAM?110:20,0);
}
// A cohesive vertical face spans chunk rows and must collapse identically in every pool.
for(let y=50;y<90;y++)for(let x=260;x<280;x++)
setCell(y*W+x,(x+y)%5===0?LCLAY:RSTONE,20,0);
addMachine('wheel',40,35,0);
for(let x=0;x<W;x++)setCell(31*W+x,STONE,20,F_NAT);
setCell(31*W+W-10,EMPTY,20,0);