Screw tubes use all their lanes: grains spread sideways inside a tube
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -91,6 +91,18 @@ function filterRun(b) {
|
||||
|
||||
// A cell a grain can be pushed into: empty, or liquid or gas that simply trades places with it
|
||||
function roomFor(j) { const t = mat[j]; return t === EMPTY || PH[t] === PH_GAS || PH[t] === PH_LIQUID; }
|
||||
// Cross one tube block, far lanes first; corners retain their liquid/gas swaps.
|
||||
function tubeSpread(c, x, y, sx, sy, intake = false) {
|
||||
const p = part[c], bx = x >> 2, by = y >> 2;
|
||||
for (;;) {
|
||||
const nx = x + sx, ny = y + sy;
|
||||
if (nx < 0 || ny < 0 || nx >= W || ny >= H || (nx >> 2) !== bx || (ny >> 2) !== by) break;
|
||||
const j = ny * W + nx;
|
||||
if (part[j] !== p || occ[j] || (intake ? mat[j] !== EMPTY || stamp[j] === tickStamp : !roomFor(j))) break;
|
||||
move(c, j, x, y, nx, ny); c = j; x = nx; y = ny;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
// An empty screw cell draws in loose material from behind it or from its sides
|
||||
// (not from the cell it pushes into), so a tube end sitting in a pile feeds itself.
|
||||
function tubeIntake(i, p, dx, dy) {
|
||||
@@ -109,6 +121,7 @@ function tubeIntake(i, p, dx, dy) {
|
||||
if (pj >= P_TU && pj <= P_TR) continue; // other tube cells move their own contents
|
||||
if (pj === P_GRATE || pj === P_FILTER) continue;
|
||||
move(j, i, nx, ny, x, y);
|
||||
if (ox !== -dx || oy !== -dy) tubeSpread(i, x, y, -ox, -oy, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-9
@@ -126,6 +126,22 @@ function machinesTick() {
|
||||
const x = i % W, y = (i / W) | 0;
|
||||
// a sideways screw carries its load along the bottom: grains settle into empty lanes below
|
||||
if (flat && y + 1 < H && part[i + W] === p && roomFor(i + W) && !occ[i + W]) { move(i, i + W, x, y, x, y + 1); continue; }
|
||||
if (!flat) {
|
||||
let own = 0, shifted = false;
|
||||
const end = dy < 0 ? (y & ~3) : (y | 3);
|
||||
for (let yy = y; dy < 0 ? yy >= end : yy <= end; yy += dy) if (PH[mat[yy * W + x]] === PH_POWDER) own++;
|
||||
const side = ((tick >> 1) + i) & 1 ? 1 : -1;
|
||||
for (let c = 0; c < 2; c++) {
|
||||
const sx = c ? -side : side, xx = x + sx, j = i + sx;
|
||||
if ((xx >> 2) !== (x >> 2) || part[j] !== p || !roomFor(j) || mat[j] !== EMPTY || occ[j] || stamp[j] === tickStamp) continue;
|
||||
let load = 0;
|
||||
for (let yy = y; dy < 0 ? yy >= end : yy <= end; yy += dy) if (PH[mat[yy * W + xx]] === PH_POWDER) load++;
|
||||
// Include this grain: a strict gap prevents a sideways step being undone next beat.
|
||||
if (own <= load + 1) continue;
|
||||
move(i, j, x, y, xx, y); stats.moved++; shifted = true; break;
|
||||
}
|
||||
if (shifted) continue;
|
||||
}
|
||||
const nx = x + dx, ny = y + dy;
|
||||
if (nx < 0 || ny < 0 || nx >= W || ny >= H) continue;
|
||||
const j = i + dj;
|
||||
@@ -143,15 +159,7 @@ function machinesTick() {
|
||||
move(i, j, x, y, nx, ny); stats.moved++;
|
||||
if (tube && pj !== p) {
|
||||
// turning a corner: keep going across the new tube's width so every lane fills
|
||||
let c = j, cx = nx, cy = ny;
|
||||
const bxj = nx >> 2, byj = ny >> 2;
|
||||
for (;;) {
|
||||
const ex = cx + dx, ey = cy + dy;
|
||||
if (ex < 0 || ey < 0 || ex >= W || ey >= H || (ex >> 2) !== bxj || (ey >> 2) !== byj) break;
|
||||
const e = ey * W + ex;
|
||||
if (part[e] !== pj || !roomFor(e) || occ[e]) break;
|
||||
move(c, e, cx, cy, ex, ey); c = e; cx = ex; cy = ey;
|
||||
}
|
||||
tubeSpread(j, nx, ny, dx, dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user