Files
deepgrain-foundry/test/t_pipes.js
T

106 lines
7.2 KiB
JavaScript

// Pipes, pumps and outlets move liquids; the Grinder grinds waste rock for trace ore.
const { load, suite, flatWorld, count } = require('./harness');
const { run } = load();
const { check, done } = suite();
const box = (x0, y0, x1, y1, m, fl = 'F_NAT') => run(`for (let y = ${y0}; y <= ${y1}; y++) for (let x = ${x0}; x <= ${x1}; x++) setCell(y * W + x, ${m}, AMB[y], ${fl})`);
const lineWater = () => run('pipeNets.reduce((a, n) => a + (n.m === WATER ? n.n : 0), 0)');
const totalWater = () => count(run, run('WATER')) + lineWater();
// two stone basins; a pump in the bottom corner of the left one pushes water up a pipe, over the
// wall and out of an outlet into the right one
function rig() {
flatWorld(run, 240, 160, 100);
run('money = 5000; bot.x = 110; bot.y = 50;');
box(36, 80, 39, 99, 'STONE'); box(72, 80, 75, 99, 'STONE'); // left basin walls
box(108, 80, 111, 99, 'STONE'); box(144, 80, 147, 99, 'STONE'); // right basin walls
box(40, 84, 71, 99, 'WATER', 0);
run(`placeBlock(BP_PUMP, 1, 17, 24, false); // pushes right, draws in from the left
for (let by = 19; by <= 23; by++) placeBlock(BP_PIPE, 0, 17, by, false);
for (let bx = 18; bx <= 28; bx++) placeBlock(BP_PIPE, 0, bx, 19, false);
placeBlock(BP_OUTLET, 0, 29, 19, false); // pours down`);
}
rig();
const w0 = totalWater(), ww0 = run('worldWater()');
run('for (let k = 0; k < 900; k++) simTick();');
const right = count(run, run('WATER'), 112, 60, 143, 99);
check('a pump, a pipe over the wall and an outlet move water from one basin to the other', right > 250, `${right} grains in the right basin, ${lineWater()} in the pipes`);
check('no water is lost or made on the way', totalWater() === w0, `${w0} -> ${totalWater()}`);
check('the weather counts water in pipes, so it sends no rain to make up for it', run('worldWater()') === ww0, `${ww0} -> ${run('worldWater()')}`);
// the line is one network: pump, 16 pipes, outlet
check('touching pipes, pump and outlet make one line', run('(rebuildPipes(), pipeNets.length)') === 1 && run('pipeNets[0].blocks.length') === 18, `${run('pipeNets.length')} lines, ${run('pipeNets[0].blocks.length')} blocks`);
// an outlet closed with F holds the water in the line; the pump stops when the line is full
rig();
run('interactAt(29 * 4 + 1, 19 * 4 + 1); for (let k = 0; k < 900; k++) simTick();');
check('with the outlet closed the line fills up and nothing comes out', count(run, run('WATER'), 112, 60, 143, 99) === 0 && lineWater() === 18 * 16, `${lineWater()} in the line`);
run('interactAt(29 * 4 + 1, 19 * 4 + 1); for (let k = 0; k < 120; k++) simTick();');
check('opened again, it pours', count(run, run('WATER'), 112, 60, 143, 99) > 50);
// taking a pipe back spills its share where it was
rig();
run('interactAt(29 * 4 + 1, 19 * 4 + 1); for (let k = 0; k < 900; k++) simTick();');
const before = totalWater();
run('removeBlock(23, 19); rebuildPipes();');
check('taking a full pipe back spills its 16 grains of water there', totalWater() === before && count(run, run('WATER'), 88, 70, 99, 99) > 0, `${before} -> ${totalWater()}`);
check('and the line is cut in two', run('pipeNets.length') === 2, run('pipeNets.length'));
// one liquid per line, and nothing hotter than 500°C
rig();
run('interactAt(29 * 4 + 1, 19 * 4 + 1); for (let k = 0; k < 60; k++) simTick();'); // outlet closed: some water stays in the line
box(40, 84, 71, 99, 'EMPTY', 0); box(40, 90, 71, 99, 'MSN', 0); run('for (let y = 90; y < 100; y++) for (let x = 40; x < 72; x++) temp[y * W + x] = 300;');
run('for (let k = 0; k < 120; k++) simTick();');
check('a line holding water will not take molten tin', count(run, run('MSN')) + count(run, run('TIN')) === 32 * 10 && run('pipeNets[0].m') === run('WATER'), `${count(run, run('MSN')) + count(run, run('TIN'))} tin left, line holds ${run('MD[pipeNets[0].m].name')}`);
rig();
box(40, 84, 71, 99, 'EMPTY', 0); box(40, 90, 71, 99, 'MCU', 0); run('for (let y = 90; y < 100; y++) for (let x = 40; x < 72; x++) temp[y * W + x] = 1200;');
run('for (let k = 0; k < 60; k++) { for (let y = 90; y < 100; y++) for (let x = 40; x < 72; x++) if (mat[y * W + x] === MCU) temp[y * W + x] = 1200; simTick(); }');
check('a pump will not take molten copper at 1200°C', run('pipeNets[0].n') === 0, run('pipeNets[0].n'));
// what is in the pipes is saved
rig();
run('interactAt(29 * 4 + 1, 19 * 4 + 1); for (let k = 0; k < 400; k++) simTick();');
const held = lineWater();
run('(() => { const s = serializeWorld(); deserializeWorld(JSON.parse(JSON.stringify(s.meta)), s.buffers); })()');
check('the water in a line survives saving and loading', held > 100 && lineWater() === held, `${held} -> ${lineWater()}`);
// pipes are thin: water and sand pass through a pipe run instead of being held back by it
flatWorld(run, 240, 160, 100);
run('money = 5000; bot.x = 60; bot.y = 50;');
box(36, 76, 39, 99, 'STONE'); box(88, 76, 91, 99, 'STONE');
run('for (let by = 19; by <= 24; by++) placeBlock(BP_PIPE, 0, 15, by, false);'); // a pipe wall at x 60..63
box(40, 80, 59, 99, 'WATER', 0);
run('for (let k = 0; k < 400; k++) simTick();');
check('water flows through a run of pipe', count(run, run('WATER'), 64, 70, 87, 99) > 60, `${count(run, run('WATER'), 64, 70, 87, 99)} grains got past`);
box(60, 64, 63, 70, 'SAND', 0); run('for (let k = 0; k < 300; k++) simTick();');
check('and sand dropped on a pipe falls down through it', count(run, run('SAND'), 40, 80, 87, 99) > 20, `${count(run, run('SAND'), 40, 80, 87, 99)} of 28 at the bottom`);
// ---- the Grinder
function grinderRig() {
flatWorld(run, 240, 160, 100);
run('money = 5000; stats.refined = 0; stats.refinedOre = 0; placeBlock(BP_GRIND, 0, 26, 15, true);');
}
function grind(feed, n) {
run(`for (let k = 0; k < ${n}; k++) {
setCell(59 * W + 104, ${feed}, AMB[59], 0); stamp[59 * W + 104] = 0;
for (let t = 0; t < 4; t++) { tick++; tickStamp++; procBlocksTick(); }
for (let t = 0; t < 12; t++) simTick();
}`);
}
grinderRig(); grind('RSTONE', 400);
const ore = () => count(run, run('CUORE')) + count(run, run('COAL')) + count(run, run('FEORE')) + count(run, run('SNORE'));
const fed = 400, sand = count(run, run('SAND')), o = ore();
check('the Grinder grinds all the stone rubble it is fed', count(run, run('RSTONE')) === 0 && run('stats.refined') === fed, `${count(run, run('RSTONE'))} left, ${run('stats.refined')} of ${fed} ground`);
check('about half as much sand comes out', sand > fed * 0.35 && sand < fed * 0.6, `${sand} sand from ${fed} rubble`);
check('with the odd grain of common ore', o > 0 && o < fed * 0.15, `${o} ore grains`);
// gravel, sand and dirt are refined too; ore drops straight through
grinderRig(); grind('LDIRT', 60);
check('dirt goes through the Grinder too', count(run, run('LDIRT')) === 0 && run('stats.refined') === 60);
grinderRig(); grind('CUORE', 30);
check('ore it cannot grind drops straight through, all of it', count(run, run('CUORE')) === 30 && count(run, run('CUORE'), 104, 59, 107, 63) === 0, count(run, run('CUORE'), 104, 59, 107, 63));
// a blocked outlet stops it
grinderRig();
box(104, 64, 107, 65, 'STONE');
run('setCell(59 * W + 104, RSTONE, AMB[59], 0); stamp[59 * W + 104] = 0; for (let k = 0; k < 8; k++) { tick++; tickStamp++; procBlocksTick(); }');
check('with the space under its outlet blocked it stops, and says so', count(run, run('RSTONE')) === 1 && run('procState.get(15 * BW + 26).blocked') === true);
done();