Screw conveyors join across the corner to diagonals (t62)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 12:12:44 -04:00
co-authored by Claude Opus 5.5
parent 828c71487c
commit ff9fd7b1b8
13 changed files with 250 additions and 99 deletions
+43
View File
@@ -48,6 +48,39 @@ for (const v of [4, 5, 6, 7]) {
const joined = drain(c,500);
check(`direction ${v}: straight to diagonal to straight`,joined.out===16 && joined.leaks===0,JSON.stringify(joined));
}
// Corner-adjacent joints: all axes, both ends, grains and queued bars.
function cornerLine(v, vertical = false) {
const s = line(v), vv = vertical ? (s.dy < 0 ? 0 : 2) : (s.dx > 0 ? 1 : 3);
const tx = s.bx-s.dx, ty = s.by-s.dy, hx = s.head+s.dx, hy = s.hy+s.dy;
run(`for(let k=0;k<3;k++) {
placeBlock(BP_SCREW,${vv},${tx}-k*${vertical?0:s.dx},${ty}-k*${vertical?s.dy:0},true);
placeBlock(BP_SCREW,${vv},${hx}+k*${vertical?0:s.dx},${hy}+k*${vertical?s.dy:0},true);
}`);
return {...s, tail:tx-2*(vertical?0:s.dx), by:ty-2*(vertical?s.dy:0),
head:hx+2*(vertical?0:s.dx), hy:hy+2*(vertical?s.dy:0)};
}
for(const v of [4,5,6,7]) for(const vertical of [false,true]) {
const s=cornerLine(v,vertical);
rect(run,s.tail*4,s.by*4,s.tail*4+3,s.by*4+3,run("SAND"));
const r=run(`(()=>{let out=0,leak=0;for(let k=0;k<700;k++){
simTick();
for(const f of flyers)if(f.m===SAND){
if(${vertical ? (s.dy<0?`f.y<${s.hy*4}`:`f.y>=${(s.hy+1)*4}`) : (s.dx<0?`f.x<${s.head*4}`:`f.x>=${(s.head+1)*4}`)})out++;else leak++;
}flyers=[];
}return {out,leak,inside:mat.reduce((n,m)=>n+(m===SAND),0)};})()`);
check(`corner ${vertical?"vertical":"horizontal"} joins ${v} carry every grain to the far mouth`,r.out===16 && !r.leak,JSON.stringify(r));
cornerLine(v,vertical);
putBar(s.tail*4,s.by*4); putBar(s.tail*4,s.by*4+2);
const bars=run(`(()=>{let out=0,overlap=false;for(let k=0;k<700;k++){
simTick();
for(let a=0;a<ents.length;a++)for(let b=0;b<a;b++) {
const e=ents[a],f=ents[b];if(e.ix<f.ix+4 && f.ix<e.ix+4 && e.iy<f.iy+2 && f.iy<e.iy+2)overlap=true;
}
if(mat.some((m,i)=>occ[i] && (PH[m]===PH_SOLID || PH[m]===PH_POWDER)))overlap=true;
for(const e of ents.slice())if(${vertical ? (s.dy<0?`e.iy+2<=${s.hy*4}`:`e.iy>=${(s.hy+1)*4}`) : (s.dx<0?`e.ix+4<=${s.head*4}`:`e.ix>=${(s.head+1)*4}`)}){out++;removeEnt(e);}
}return {out,overlap,left:ents.length};})()`);
check(`corner ${vertical?"vertical":"horizontal"} joins ${v} carry queued bars`,bars.out===2 && !bars.overlap,JSON.stringify(bars));
}
// A saturated ten-block line: 80 warmup ticks, then 600 measured ticks at 60 Hz.
const rates = [];
for (const v of [0, 4, 5]) {
@@ -169,7 +202,17 @@ for(const [dx,dy,v] of [[5,-4,4],[4,5,5],[-5,4,6],[-4,-5,7]]) {
check(`direction ${v} lays a corner-touching diagonal run`,run(`blockLine(20,20,${20+dx},${20+dy},true).every(([x,y],k)=>x===20+k*${Math.sign(dx)} && y===20+k*${Math.sign(dy)})`));
}
// End elbows follow the adjoining straight piece's axis, regardless of flow direction.
run(fs.readFileSync('src/render/diagonal-screws.js', 'utf8'));
run(fs.readFileSync('src/render/world.js', 'utf8'));
for (const v of [4,5,6,7]) for (const end of [-1,1]) for (let dir=0;dir<4;dir++) {
fresh();
const slope=v===4 || v===6?-1:1, nx=20+end, ny=20+end*slope, shift=end>0?3:0;
run(`placeBlock(BP_SCREW,${v},20,20,true);placeBlock(BP_SCREW,${dir},${nx},${ny},true);`);
const expected=dir&1?5:6;
check(`corner ${v} end ${end} straight ${dir} selects a closed elbow`,run(`(()=>{const j=diagonalScrewJoins(20,20,${v});return (j>>${shift}&7)===${expected} && !(j&${end>0?128:64});})()`));
check(`corner ${v} end ${end} straight ${dir} meets all four mouth lanes`,run(`(()=>{const j=diagonalScrewJoins(20,20,${v});return [0.5,1.5,2.5,3.5].every(t=>diagonalScrewShape(${dir&1?82+end*1.99:"80+t+"+end*4},${dir&1?"80+t+"+end*slope*4:82+end*slope*1.99},20*BW+20,${v},j)<=0);})()`));
check(`corner ${v} end ${end} straight ${dir} planned joins match placed joins`,run(`(()=>{const j=diagonalScrewJoins(20,20,${v});removeBlock(${nx},${ny});return diagonalScrewJoins(20,20,${v},new Map([[${ny}*BW+${nx},[BP_SCREW,${dir}]]]))===j;})()`));
}
for (const v of [4,5,6,7]) for (let dir=0;dir<4;dir++) for (const code of ['BP_SCREW','BP_BELT','BP_FILTER']) {
if (code !== 'BP_SCREW' && !(dir & 1)) continue;
fresh();