Rename screw tubes to screw conveyors (t44)
Player text says Screw conveyor; code uses screw (BP_SCREW, piece id screw, screwIntake...). No compatibility code for old saves or blueprints. Suite outputs match before and after apart from names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+48
-48
@@ -1,9 +1,9 @@
|
||||
// Screw tubes that never carry liquid (it flows through), tube and belt throughput, filters.
|
||||
// Screw conveyors that never carry liquid (it flows through), screw and belt throughput, filters.
|
||||
const { load, suite, flatWorld, rect, ticks, count } = require('./harness');
|
||||
const { run } = load();
|
||||
const { check, done } = suite();
|
||||
function fresh() { flatWorld(run, 320, 200, 120); run('bot.x = 20; bot.y = 40; money = 1e6; globalThis.__got = 0;'); }
|
||||
const tubeLiquid = () => run('(() => { let n = 0; for (let i = 0; i < N; i++) if (part[i] >= P_TU && part[i] <= P_TR && PH[mat[i]] === PH_LIQUID) n++; return n; })()');
|
||||
const screwLiquid = () => run('(() => { let n = 0; for (let i = 0; i < N; i++) if (part[i] >= P_SCREW_U && part[i] <= P_SCREW_R && PH[mat[i]] === PH_LIQUID) n++; return n; })()');
|
||||
// grains that land in the sink region are counted and taken away, so outlets never back up
|
||||
function rate(x0, x1, y0, y1, warm, meas) {
|
||||
const sink = `for (let y=${y0};y<=${y1};y++) for (let x=${x0};x<=${x1};x++) { const i=y*W+x; if (mat[i]===SAND) { mat[i]=EMPTY; __got++; } }`;
|
||||
@@ -13,42 +13,42 @@ function rate(x0, x1, y0, y1, warm, meas) {
|
||||
return run('__got') / (meas / 60);
|
||||
}
|
||||
|
||||
// --- tubes are sealed: no water in, no water carried
|
||||
// --- screws are sealed: no water in, no water carried
|
||||
fresh();
|
||||
run('for (let y = 120; y < 170; y++) for (let x = 100; x < 124; x++) setCell(y*W+x, EMPTY, AMB[y], 0)');
|
||||
rect(run, 100, 150, 123, 169, run('SAND'));
|
||||
rect(run, 100, 130, 123, 149, run('WATER'));
|
||||
run('for (let by = 22; by <= 41; by++) placeBlock(BP_TUBE, 0, 27, by, true); for (let bx = 27; bx <= 34; bx++) placeBlock(BP_TUBE, 1, bx, 21, true);');
|
||||
run('for (let by = 22; by <= 41; by++) placeBlock(BP_SCREW, 0, 27, by, true); for (let bx = 27; bx <= 34; bx++) placeBlock(BP_SCREW, 1, bx, 21, true);');
|
||||
const water0 = count(run, run('WATER'));
|
||||
ticks(run, 900);
|
||||
const wOut = count(run, run('WATER'), 124, 0, 319, 119), sOut = count(run, run('SAND'), 124, 0, 319, 119);
|
||||
check('a lift standing in a flooded pit brings up the sand but not the water', sOut > 150 && wOut === 0, `sand out ${sOut}, water out ${wOut}, water standing in the tubes ${tubeLiquid()}`);
|
||||
check('a lift standing in a flooded pit brings up the sand but not the water', sOut > 150 && wOut === 0, `sand out ${sOut}, water out ${wOut}, water standing in the screws ${screwLiquid()}`);
|
||||
const pitClouds = run('weather.moist.reduce((a, v) => a + v, 0)');
|
||||
const pitSteam = count(run, run('STEAM')); // the pit's floor is hot: some is steam on its way up at any moment
|
||||
check('the pit keeps its water (bar what steams off into the clouds)', water0 - count(run, run('WATER')) - pitSteam - pitClouds <= 6, `${water0} -> ${count(run, run('WATER'))}, ${pitSteam} steam, ${pitClouds.toFixed(0)} in the clouds`);
|
||||
fresh();
|
||||
run('for (let bx = 20; bx < 26; bx++) placeBlock(BP_TUBE, 1, bx, 25, true);');
|
||||
run('for (let bx = 20; bx < 26; bx++) placeBlock(BP_SCREW, 1, bx, 25, true);');
|
||||
rect(run, 84, 60, 95, 79, run('WATER'));
|
||||
ticks(run, 300);
|
||||
check('water poured on a tube runs straight through it', count(run, run('WATER'), 0, 0, 319, 99) === 0 && count(run, run('WATER'), 0, 104, 319, 119) > 200 && tubeLiquid() < 10, `${count(run, run('WATER'), 0, 104, 319, 119)} below, ${tubeLiquid()} still inside`);
|
||||
check('water poured on a screw runs straight through it', count(run, run('WATER'), 0, 0, 319, 99) === 0 && count(run, run('WATER'), 0, 104, 319, 119) > 200 && screwLiquid() < 10, `${count(run, run('WATER'), 0, 104, 319, 119)} below, ${screwLiquid()} still inside`);
|
||||
fresh();
|
||||
// a vertical tube pointing up, its top open to a pool: the water drains down through it, against the screw
|
||||
run('for (let by = 20; by <= 26; by++) placeBlock(BP_TUBE, 0, 25, by, true); for (let y = 60; y < 80; y++) { setCell(y*W+99, STONE, AMB[y], 0); setCell(y*W+104, STONE, AMB[y], 0); }');
|
||||
// a vertical screw pointing up, its top open to a pool: the water drains down through it, against the screw
|
||||
run('for (let by = 20; by <= 26; by++) placeBlock(BP_SCREW, 0, 25, by, true); for (let y = 60; y < 80; y++) { setCell(y*W+99, STONE, AMB[y], 0); setCell(y*W+104, STONE, AMB[y], 0); }');
|
||||
rect(run, 100, 60, 103, 79, run('WATER'));
|
||||
ticks(run, 400);
|
||||
check('water runs down through an upward screw, which never pushes it back', count(run, run('WATER'), 0, 0, 319, 79) === 0, count(run, run('WATER'), 0, 0, 319, 79));
|
||||
|
||||
// Intake itself fills the far lanes first, for either tube axis.
|
||||
// Intake itself fills the far lanes first, for either screw axis.
|
||||
for (const horizontal of [false, true]) {
|
||||
fresh();
|
||||
run(`placeBlock(BP_TUBE, ${horizontal ? 1 : 0}, 25, 20, true);`);
|
||||
run(`placeBlock(BP_SCREW, ${horizontal ? 1 : 0}, 25, 20, true);`);
|
||||
const filled = run(`(() => {
|
||||
const lanes = [];
|
||||
for (let k = 0; k < BS; k++) {
|
||||
tickStamp++;
|
||||
const x = ${horizontal ? 100 : 99}, y = ${horizontal ? 79 : 80};
|
||||
setCell(y*W+x, SAND, AMB[y], 0);
|
||||
tubeIntake(80*W+100, ${horizontal ? 'P_TR, 1, 0' : 'P_TU, 0, -1'});
|
||||
screwIntake(80*W+100, ${horizontal ? 'P_SCREW_R, 1, 0' : 'P_SCREW_U, 0, -1'});
|
||||
for (let lane = 0; lane < BS; lane++) if (mat[(80+${horizontal ? 'lane' : '0'})*W+100+${horizontal ? '0' : 'lane'}] === SAND && !lanes.includes(lane)) lanes.push(lane);
|
||||
}
|
||||
return lanes;
|
||||
@@ -59,7 +59,7 @@ for (const horizontal of [false, true]) {
|
||||
// A finite heap rides into the side of a six-block lift; remove each mouth flyer once.
|
||||
const sideSeed = run('RS');
|
||||
fresh();
|
||||
run('RS = 7; for (let bx = 16; bx < 32; bx++) placeBlock(BP_BELT, 1, bx, 25, true); for (let by = 19; by <= 24; by++) placeBlock(BP_TUBE, 0, 32, by, true);');
|
||||
run('RS = 7; for (let bx = 16; bx < 32; bx++) placeBlock(BP_BELT, 1, bx, 25, true); for (let by = 19; by <= 24; by++) placeBlock(BP_SCREW, 0, 32, by, true);');
|
||||
rect(run, 64, 40, 119, 99, run('SAND'));
|
||||
const sideLift = run(`(() => {
|
||||
let out = 0; const lanes = [0, 0, 0, 0];
|
||||
@@ -79,7 +79,7 @@ check('the side-fed lift conserves its sand, including mouth flyers', sideLift.b
|
||||
// The same belt and heap deliver 2243 into an open drop, the most the lift can be given.
|
||||
check('a side-fed lift carries at least 90% of what its belt brings (it was 65%)', sideLift.out >= Math.floor(0.9 * 2243), sideLift.out);
|
||||
|
||||
// Same belt and finite heap, with a non-blocking sink at the tube side.
|
||||
// Same belt and finite heap, with a non-blocking sink at the screw side.
|
||||
run(`RS = ${sideSeed}`);
|
||||
fresh();
|
||||
run('RS = 7; for (let bx = 16; bx < 32; bx++) placeBlock(BP_BELT, 1, bx, 25, true);');
|
||||
@@ -100,24 +100,24 @@ console.log('Belt delivery to a non-blocking sink, 3000 ticks: ' + beltDelivery)
|
||||
|
||||
// --- throughput
|
||||
fresh();
|
||||
run('for (let bx = 20; bx < 30; bx++) placeBlock(BP_TUBE, 1, bx, 20, true);');
|
||||
run('for (let bx = 20; bx < 30; bx++) placeBlock(BP_SCREW, 1, bx, 20, true);');
|
||||
run('for (let y = 0; y < 80; y++) { setCell(y*W+79, STONE, AMB[y], 0); setCell(y*W+96, STONE, AMB[y], 0); }');
|
||||
rect(run, 80, 0, 95, 79, run('SAND'));
|
||||
ticks(run, 60);
|
||||
const lanes = run('(() => { const s = new Set(); for (let y = 80; y < 84; y++) for (let x = 100; x < 120; x++) if (mat[y*W+x] === SAND) s.add(y); return s.size; })()');
|
||||
check('a sideways tube fed from above (its side) fills more than one row', lanes > 1, lanes);
|
||||
check('a sideways tube fed from a hopper runs full, all four grains wide', lanes === 4, lanes);
|
||||
check('a sideways screw fed from above (its side) fills more than one row', lanes > 1, lanes);
|
||||
check('a sideways screw fed from a hopper runs full, all four grains wide', lanes === 4, lanes);
|
||||
fresh();
|
||||
run('for (let bx = 20; bx < 30; bx++) placeBlock(BP_TUBE, 1, bx, 20, true);');
|
||||
run('for (let bx = 20; bx < 30; bx++) placeBlock(BP_SCREW, 1, bx, 20, true);');
|
||||
run('for (let y = 0; y < 80; y++) { setCell(y*W+79, STONE, AMB[y], 0); setCell(y*W+96, STONE, AMB[y], 0); }');
|
||||
rect(run, 80, 0, 95, 79, run('SAND'));
|
||||
const tr = rate(120, 319, 84, 119, 90, 300);
|
||||
// tubes run at belt pace (every other tick), so a belt under a tube's mouth keeps up with it
|
||||
check('a sideways tube moves around a hundred grains a second', tr > 80 && tr < 150, `${tr.toFixed(0)}/s`);
|
||||
// screws run at belt pace (every other tick), so a belt under a screw's mouth keeps up with it
|
||||
check('a sideways screw moves around a hundred grains a second', tr > 80 && tr < 150, `${tr.toFixed(0)}/s`);
|
||||
fresh();
|
||||
run('for (let y = 120; y < 196; y++) for (let x = 90; x < 130; x++) setCell(y*W+x, EMPTY, AMB[y], 0)');
|
||||
rect(run, 90, 130, 129, 195, run('SAND'));
|
||||
run('for (let by = 20; by <= 37; by++) placeBlock(BP_TUBE, 0, 26, by, true); for (let bx = 26; bx <= 40; bx++) placeBlock(BP_TUBE, 1, bx, 19, true);');
|
||||
run('for (let by = 20; by <= 37; by++) placeBlock(BP_SCREW, 0, 26, by, true); for (let bx = 26; bx <= 40; bx++) placeBlock(BP_SCREW, 1, bx, 19, true);');
|
||||
const lr = rate(164, 319, 80, 119, 400, 300);
|
||||
const liftLanes = run('(() => { const s = new Set(); for (let y = 76; y < 80; y++) for (let x = 120; x < 160; x++) if (mat[y*W+x] === SAND) s.add(y); return s.size; })()');
|
||||
check('a lift turns its corner without squeezing down to one lane', liftLanes === 4 && lr > 30, `${lr.toFixed(0)}/s, ${liftLanes} lanes at the top`);
|
||||
@@ -151,7 +151,7 @@ check('the load rides a belt up to a block deep', depth >= 3, depth);
|
||||
// --- filters
|
||||
fresh();
|
||||
// a filter for copper ore under a mixed pile; everything else rides right and off the end
|
||||
// fed from a walled hopper over its left end, the way a tube or belt would drop a mixed load on it
|
||||
// fed from a walled hopper over its left end, the way a screw or belt would drop a mixed load on it
|
||||
run('for (let bx = 20; bx < 30; bx++) placeBlock(BP_FILTER, 128, bx, 25, true, { m: [CUORE] });');
|
||||
run('for (let y = 30; y < 120; y++) setCell(y*W+79, STONE, AMB[y], 0); for (let y = 30; y < 96; y++) setCell(y*W+88, STONE, AMB[y], 0);');
|
||||
run('for (let y = 40; y < 96; y++) for (let x = 80; x < 88; x++) setCell(y*W+x, (x + y) % 3 ? SAND : CUORE, AMB[y], 0)');
|
||||
@@ -236,7 +236,7 @@ run(`globalThis.__carry = carryColumn;
|
||||
for (const lift of [true, false]) {
|
||||
fresh();
|
||||
run('RS = 7; __shear = 0; for (let bx = 20; bx < 32; bx++) placeBlock(BP_BELT, 1, bx, 25, true);');
|
||||
if (lift) run('for (let by = 15; by <= 24; by++) placeBlock(BP_TUBE, 0, 32, by, true);');
|
||||
if (lift) run('for (let by = 15; by <= 24; by++) placeBlock(BP_SCREW, 0, 32, by, true);');
|
||||
else run('for (let by = 10; by <= 25; by++) placeBlock(BP_WALL, RSTONE, 32, by, true);');
|
||||
rect(run, 88, 94, 119, 99, run('SAND'));
|
||||
rect(run, 88, 70, 119, 93, run('CUORE'));
|
||||
@@ -251,60 +251,60 @@ for (const lift of [true, false]) {
|
||||
}
|
||||
run('carryColumn = __carry;');
|
||||
|
||||
// --- whole bars in screw tubes; position an existing bar inside for mid-ride cases
|
||||
// --- whole bars in screw conveyors; position an existing bar inside for mid-ride cases
|
||||
function putBar(x, y) { run(`{ spawnBar(BARCU, 20, 40, 0, 0); const e=ents[0]; entMark(e,0); e.x=e.ix=${x}; e.y=e.iy=${y}; entMark(e,1); }`); }
|
||||
function barTube(corner = false) {
|
||||
function barScrew(corner = false) {
|
||||
fresh();
|
||||
run(`for (let by = 20; by < 24; by++) placeBlock(BP_TUBE, 0, 25, by, true);
|
||||
${corner ? 'for (let bx = 25; bx < 29; bx++) placeBlock(BP_TUBE, 1, bx, 19, true);' : ''}`);
|
||||
run(`for (let by = 20; by < 24; by++) placeBlock(BP_SCREW, 0, 25, by, true);
|
||||
${corner ? 'for (let bx = 25; bx < 29; bx++) placeBlock(BP_SCREW, 1, bx, 19, true);' : ''}`);
|
||||
putBar(100,94);
|
||||
}
|
||||
function watchBar(n, condition) { return run(`(() => { for (let k=0;k<${n};k++) { simTick(); if (${condition}) return true; } return false; })()`); }
|
||||
fresh();
|
||||
run('for (let bx=20;bx<25;bx++) placeBlock(BP_BELT,1,bx,25,true); for(let by=21;by<25;by++) placeBlock(BP_TUBE,0,25,by,true); spawnBar(BARCU,84,98,0,0);');
|
||||
run('for (let bx=20;bx<25;bx++) placeBlock(BP_BELT,1,bx,25,true); for(let by=21;by<25;by++) placeBlock(BP_SCREW,0,25,by,true); spawnBar(BARCU,84,98,0,0);');
|
||||
check('a belt feeds a whole copper bar into a lift and out its top', watchBar(200, 'ents.length===1 && ents[0].iy+BAR_H<=84'), run('JSON.stringify(ents)'));
|
||||
fresh();
|
||||
run('for(let bx=20;bx<24;bx++) placeBlock(BP_TUBE,1,bx,20,true);'); putBar(80,82);
|
||||
check('a whole bar leaves a right tube', watchBar(100,'ents.length===1 && ents[0].ix>=96'));
|
||||
// steam and smoke drift through tubes near furnaces: a bar passes them as it does in the open
|
||||
barTube();
|
||||
check('steam and smoke in a tube do not stop a bar', run(`(() => { for (let k = 0; k < 120; k++) {
|
||||
run('for(let bx=20;bx<24;bx++) placeBlock(BP_SCREW,1,bx,20,true);'); putBar(80,82);
|
||||
check('a whole bar leaves a right screw', watchBar(100,'ents.length===1 && ents[0].ix>=96'));
|
||||
// steam and smoke drift through screws near furnaces: a bar passes them as it does in the open
|
||||
barScrew();
|
||||
check('steam and smoke in a screw do not stop a bar', run(`(() => { for (let k = 0; k < 120; k++) {
|
||||
for (let y = 80; y < 94; y++) for (let x = 100; x < 104; x++) if (mat[y*W+x] === EMPTY && !occ[y*W+x]) setCell(y*W+x, (x + y) & 1 ? STEAM : SMOKE, 120, 0);
|
||||
simTick(); if (ents.length === 1 && ents[0].iy + BAR_H <= 80) return true; } return false; })()`), run('JSON.stringify(ents)'));
|
||||
barTube(true);
|
||||
check('a bar turns from an up tube into a right tube and leaves', watchBar(200,'ents.length===1 && ents[0].ix>=116'));
|
||||
barScrew(true);
|
||||
check('a bar turns from an up screw into a right screw and leaves', watchBar(200,'ents.length===1 && ents[0].ix>=116'));
|
||||
fresh();
|
||||
run('for(let bx=20;bx<24;bx++) placeBlock(BP_TUBE,1,bx,20,true);'); putBar(80,82);
|
||||
run('for(let bx=20;bx<24;bx++) placeBlock(BP_SCREW,1,bx,20,true);'); putBar(80,82);
|
||||
rect(run,96,80,99,83,run('STONE'));
|
||||
ticks(run,100);
|
||||
check('a blocked mouth holds the whole bar inside without wall overlap',run('ents.length===1 && ents[0].ix===92 && !mat.some((m,i)=>m===STONE && occ[i])'),run('JSON.stringify(ents)'));
|
||||
rect(run,96,80,99,83,run('EMPTY'));
|
||||
check('the bar leaves when the mouth wall is removed',watchBar(80,'ents[0].ix>=96'));
|
||||
barTube();
|
||||
barScrew();
|
||||
rect(run,100,88,103,89,run('SAND'));
|
||||
const shared = run(`(() => { let overlap=false, rose=false; const n=mat.reduce((n,m)=>n+(m===SAND),0); for(let k=0;k<160;k++) { simTick(); if(mat.some((m,i)=>m===SAND && occ[i])) overlap=true; if(ents[0].iy<90) rose=true; } return { overlap, rose, n, after:mat.reduce((n,m)=>n+(m===SAND),0)+flyers.filter(f=>f.m===SAND).length }; })()`);
|
||||
check('grains and a moving bar share a lift without overlap or lost sand',!shared.overlap && shared.rose && shared.n===shared.after,JSON.stringify(shared));
|
||||
barTube(); ticks(run,8);
|
||||
barScrew(); ticks(run,8);
|
||||
run('globalThis.__barSave=serializeWorld(); deserializeWorld(__barSave.meta,__barSave.buffers);');
|
||||
check('a bar saved mid-tube continues out of its mouth',watchBar(100,'ents.length===1 && ents[0].iy+BAR_H<=80'));
|
||||
check('a bar saved mid-screw continues out of its mouth',watchBar(100,'ents.length===1 && ents[0].iy+BAR_H<=80'));
|
||||
fresh();
|
||||
run('for(let bx=20;bx<24;bx++) placeBlock(BP_BELT,1,bx,25,true); placeBlock(BP_WALL,RSTONE,24,25,true); placeBlock(BP_WALL,RSTONE,24,24,true); spawnBar(BARCU,80,98,0,0);');
|
||||
ticks(run,100);
|
||||
check('a normal belt still carries a bar and stops at its blocked end',run('ents.length===1 && ents[0].ix===92 && ents[0].iy===98'));
|
||||
fresh(); run('placeBlock(BP_TUBE,1,25,25,true); spawnBar(BARCU,100,98,0,0);'); ticks(run,100);
|
||||
check('a bar resting on a horizontal tube stays on top',run('ents[0].ix===100 && ents[0].iy===98'));
|
||||
fresh(); run('placeBlock(BP_SCREW,1,25,25,true); spawnBar(BARCU,100,98,0,0);'); ticks(run,100);
|
||||
check('a bar resting on a horizontal screw stays on top',run('ents[0].ix===100 && ents[0].iy===98'));
|
||||
|
||||
for (const dir of [0, 2]) {
|
||||
fresh(); run(`placeBlock(BP_TUBE,${dir},25,20,true); spawnBar(BARCU,100,${dir ? 78 : 84},0,${dir ? 0 : -0.4});`);
|
||||
check(dir ? 'a falling bar enters a down tube from above' : 'an upward moving bar enters the bottom of an up tube',watchBar(20,'entTubeAt(ents[0].ix,ents[0].iy)!==0'));
|
||||
fresh(); run(`placeBlock(BP_SCREW,${dir},25,20,true); spawnBar(BARCU,100,${dir ? 78 : 84},0,${dir ? 0 : -0.4});`);
|
||||
check(dir ? 'a falling bar enters a down screw from above' : 'an upward moving bar enters the bottom of an up screw',watchBar(20,'entScrewAt(ents[0].ix,ents[0].iy)!==0'));
|
||||
}
|
||||
fresh(); run('for(let bx=20;bx<24;bx++) placeBlock(BP_TUBE,1,bx,20,true); for(let by=21;by<25;by++) placeBlock(BP_TUBE,2,23,by,true);'); putBar(80,82);
|
||||
check('a bar turns from a right tube down into a vertical lane',watchBar(160,'ents[0].iy>=100'));
|
||||
barTube(true); rect(run,100,76,103,79,run('STONE')); ticks(run,100);
|
||||
fresh(); run('for(let bx=20;bx<24;bx++) placeBlock(BP_SCREW,1,bx,20,true); for(let by=21;by<25;by++) placeBlock(BP_SCREW,2,23,by,true);'); putBar(80,82);
|
||||
check('a bar turns from a right screw down into a vertical lane',watchBar(160,'ents[0].iy>=100'));
|
||||
barScrew(true); rect(run,100,76,103,79,run('STONE')); ticks(run,100);
|
||||
check('a blocked corner waits without overlapping stone',run('ents[0].iy===80 && !mat.some((m,i)=>m===STONE && occ[i])'));
|
||||
rect(run,100,76,103,79,run('EMPTY'));
|
||||
check('a blocked corner resumes when cleared',watchBar(120,'ents[0].ix>=116'));
|
||||
barTube(); run('ents[0].T=1200; for(let y=94;y<96;y++) for(let x=100;x<104;x++) temp[y*W+x]=1200; entTick();');
|
||||
check('a bar melting inside a tube becomes eight molten grains',run('ents.length===0') && count(run,run('MCU'))===8);
|
||||
barScrew(); run('ents[0].T=1200; for(let y=94;y<96;y++) for(let x=100;x<104;x++) temp[y*W+x]=1200; entTick();');
|
||||
check('a bar melting inside a screw becomes eight molten grains',run('ents.length===0') && count(run,run('MCU'))===8);
|
||||
|
||||
done();
|
||||
|
||||
Reference in New Issue
Block a user