Corner placements of screw conveyors stay separate ends (t62 follow-up)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+30
-34
@@ -48,38 +48,35 @@ 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++;
|
||||
// Corner placements are separate mouths, on both axes and in either transfer direction.
|
||||
for (const v of [4,5,6,7]) for (const vertical of [false,true]) for (const fromDiagonal of [false,true]) {
|
||||
fresh();
|
||||
const [dx,dy]=run(`SCREW_DIRS[${v}]`), sv=vertical?(dy<0?0:2):(dx>0?1:3);
|
||||
const sx=20+(fromDiagonal?0:-dx), sy=20+(fromDiagonal?0:-dy);
|
||||
const tx=20+(fromDiagonal?dx:0), ty=20+(fromDiagonal?dy:0);
|
||||
const source=fromDiagonal?v:sv, target=fromDiagonal?sv:v;
|
||||
const label=`corner ${vertical?'vertical':'horizontal'} ${v} ${fromDiagonal?'diagonal to straight':'straight to diagonal'}`;
|
||||
run(`placeBlock(BP_SCREW,${source},${sx},${sy},true);placeBlock(BP_SCREW,${target},${tx},${ty},true);rebuildPower();`);
|
||||
rect(run,sx*4,sy*4,sx*4+3,sy*4+3,run('SAND'));
|
||||
const grains=run(`(()=>{let crossed=0;for(let k=0;k<80;k++){
|
||||
tick+=2;tickStamp++;machinesTick();
|
||||
for(let i=0;i<N;i++)if(mat[i]===SAND){
|
||||
const x=i%W>>2,y=(i/W|0)>>2;
|
||||
if(x===${tx} && y===${ty})crossed++;
|
||||
if(x!==${sx} || y!==${sy})setCell(i,EMPTY,20,0);
|
||||
}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));
|
||||
}return crossed;})()`);
|
||||
check(`${label} does not pass grains`,grains===0,grains);
|
||||
run('mat.forEach((m,i)=>{if(m===SAND)setCell(i,EMPTY,20,0);});');
|
||||
for(const lane of [0,1,2]) {
|
||||
putBar(sx*4,sy*4+lane);
|
||||
const bar=run(`(()=>{const e=ents[0];let crossed=false;for(let k=0;k<80;k++){
|
||||
tick+=8;entMark(e,0);entScrewTick(e,SCREW_PARTS[${source}]);entMark(e,1);
|
||||
if((e.ix>>2)===${tx} && (e.iy>>2)===${ty})crossed=true;
|
||||
if(!entScrewAt(e.ix,e.iy))break;
|
||||
}removeEnt(e);return crossed;})()`);
|
||||
check(`${label} does not pass a bar in lane ${lane}`,!bar);
|
||||
}
|
||||
}
|
||||
// A saturated ten-block line: 80 warmup ticks, then 600 measured ticks at 60 Hz.
|
||||
const rates = [];
|
||||
@@ -208,9 +205,8 @@ 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} keeps its free-end collar`,run(`(()=>{const j=diagonalScrewJoins(20,20,${v});return (j>>${shift}&7)===0 && !!(j&${end>0?128:64});})()`));
|
||||
check(`corner ${v} end ${end} straight ${dir} leaves the free-end geometry unchanged`,run(`(()=>{const b=20*BW+20,j=diagonalScrewJoins(20,20,${v});removeBlock(${nx},${ny});const alone=diagonalScrewJoins(20,20,${v});placeBlock(BP_SCREW,${dir},${nx},${ny},true);return j===alone && [0.5,1.5,2.5,3.5].every(t=>diagonalScrewShape(82+${end}*2,80+t,b,${v},j)===diagonalScrewShape(82+${end}*2,80+t,b,${v},alone));})()`));
|
||||
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']) {
|
||||
|
||||
+43
-19
@@ -97,34 +97,58 @@ with sync_playwright() as p:
|
||||
}''')
|
||||
check('sidewall stays behind the grain colour in pixels and smooth',
|
||||
wall and wall['colors'][0] == wall['colors'][1] and wall['grainClass'] == 2, wall)
|
||||
# All 64 straight/diagonal mouths must have copper casing on both sides of the join.
|
||||
# Edge joins keep closed elbows; corner placements match two isolated free ends.
|
||||
pg.set_viewport_size({"width": 2100, "height": 1300})
|
||||
ev("part.fill(0); blockP.fill(0); occ.fill(0); mach.fill(0); ents=[]; ghostBlocks.clear();")
|
||||
ev("() => {" + (root / "tools/scenes/t62-joins.js").read_text() + "}")
|
||||
mouths = ev('''() => {
|
||||
SET.zoom=6; SET.lighting="off"; SET.glow="off"; resizeRender();
|
||||
bot.x=CAM[0]-bot.w/2;bot.y=CAM[1]-bot.h/2;snapCamera();
|
||||
const out={};
|
||||
for(const look of ["pixel","smooth"]) {
|
||||
SET.look=look;SM.scale=1;drawWorld();
|
||||
const bad=[];
|
||||
for(const j of T62_JOINTS) {
|
||||
const slope=j.v===4 || j.v===6?-1:1;
|
||||
const end=j.end*SCREW_DIRS[j.v][0];
|
||||
const dx=j.vertical?0:end,dy=j.vertical?end*slope:0;
|
||||
const ox=j.corner && j.vertical?end*4:0,oy=j.corner && !j.vertical?end*slope*4:0;
|
||||
for(const side of [-1,1])for(const along of [-0.3,0.3]) {
|
||||
const x=j.bx*4+2+ox+dx*(2+along)-dy*side*1.6;
|
||||
const y=j.by*4+2+oy+dy*(2+along)+dx*side*1.6;
|
||||
const p=worldToScreenPx(x,y),c=R.ctx.getImageData(Math.floor(p.x),Math.floor(p.y),1,1).data;
|
||||
if(!(c[0]>c[1]*1.15 && c[1]>c[2]*1.1))bad.push([j,x,y,Array.from(c)]);
|
||||
const now=performance.now.bind(performance),frozen=now();
|
||||
performance.now=()=>frozen;
|
||||
try {
|
||||
const out={};
|
||||
const draw=()=>{SM.scale=1;drawWorld();};
|
||||
for(const look of ["pixel","smooth"]) {
|
||||
SET.look=look;draw();
|
||||
const bad=[];
|
||||
for(const j of T62_JOINTS) {
|
||||
const slope=j.v===4 || j.v===6?-1:1;
|
||||
const end=j.end*SCREW_DIRS[j.v][0];
|
||||
const dx=j.vertical?0:end,dy=j.vertical?end*slope:0;
|
||||
if(j.corner)continue;
|
||||
for(const side of [-1,1])for(const along of [-0.3,0.3]) {
|
||||
const x=j.bx*4+2+dx*(2+along)-dy*side*1.6;
|
||||
const y=j.by*4+2+dy*(2+along)+dx*side*1.6;
|
||||
const p=worldToScreenPx(x,y),c=R.ctx.getImageData(Math.floor(p.x),Math.floor(p.y),1,1).data;
|
||||
if(!(c[0]>c[1]*1.15 && c[1]>c[2]*1.1))bad.push([j,x,y,Array.from(c)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
out[look]=bad;
|
||||
}return out;
|
||||
const sample=(bx,by)=>{
|
||||
const colors=[];
|
||||
for(let y=0;y<4;y++)for(let x=0;x<4;x++) {
|
||||
const p=worldToScreenPx(bx*4+x+0.5,by*4+y+0.5);
|
||||
colors.push(...R.ctx.getImageData(Math.floor(p.x),Math.floor(p.y),1,1).data);
|
||||
}return colors.join(',');
|
||||
};
|
||||
for(const j of T62_JOINTS.filter(j=>j.corner)) {
|
||||
const [dx,dy]=SCREW_DIRS[j.v],sx=j.bx+j.end*dx,sy=j.by+j.end*dy;
|
||||
const collar=sample(j.bx,j.by),straight=sample(sx,sy);
|
||||
const joins=diagonalScrewJoins(j.bx,j.by,j.v),end=j.end*dx>0?1:0;
|
||||
if(!(joins & (64<<end)) || (joins>>(end*3)&7))bad.push(['missing collar',j]);
|
||||
removeBlock(sx,sy);draw();
|
||||
if(sample(j.bx,j.by)!==collar)bad.push(['diagonal differs from isolated end',j]);
|
||||
placeBlock(BP_SCREW,j.straight,sx,sy,true);
|
||||
removeBlock(j.bx,j.by);draw();
|
||||
if(sample(sx,sy)!==straight)bad.push(['straight differs from normal end',j]);
|
||||
placeBlock(BP_SCREW,j.v,j.bx,j.by,true);draw();
|
||||
}
|
||||
out[look]=bad;
|
||||
}return out;
|
||||
} finally {performance.now=now;}
|
||||
}''')
|
||||
for look, bad in mouths.items():
|
||||
check(f"{look}: all 64 screw joints have closed casing across both mouth edges", not bad, bad[:2])
|
||||
check(f"{look}: edge elbows stay closed and corners show two separate free ends", not bad, bad[:2])
|
||||
# a browser without hardware drawing gets the pixel look and a note
|
||||
pg2 = b.new_page(viewport={'width': 800, 'height': 500})
|
||||
pg2.add_init_script('localStorage.clear();')
|
||||
|
||||
Reference in New Issue
Block a user