Diagonal screw tubes, laid by a 45° drag (t35)

- Tubes run in eight directions: a drag at about 45° lays a diagonal run, R cycles all eight.
- Diagonal runs carry grains at the straight rate (120 grains/s), join straight tubes and belts,
  keep grains in at the corners, pass water, and carry bars level.
- New part ids 11-14 (saved ids are never renumbered); tube checks use an IS_TUBE table.
- New test/t_diag_tubes.js (85 checks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 17:37:30 -04:00
co-authored by Claude Opus 5.5
parent 381019b7aa
commit 8087c28cb5
26 changed files with 348 additions and 65 deletions
+23 -4
View File
@@ -108,10 +108,11 @@ function tubeSpread(c, x, y, sx, sy, intake = false) {
function tubeIntake(i, p, dx, dy) {
if (occ[i]) return;
const x = i % W, y = (i / W) | 0;
const cands = [[-dx, -dy], [dy, dx], [-dy, -dx]];
const start = (tick + i) % 3;
for (let c = 0; c < 3; c++) {
const [ox, oy] = cands[(start + c) % 3];
const k = (start + c) % 3, diagonal = dx && dy;
const ox = diagonal ? (k === 1 ? 0 : -dx) : k === 0 ? -dx : k === 1 ? dy : -dy;
const oy = diagonal ? (k === 0 ? 0 : -dy) : k === 0 ? -dy : k === 1 ? dx : -dx;
const nx = x + ox, ny = y + oy;
if (nx < 0 || ny < 0 || nx >= W || ny >= H) continue;
const j = ny * W + nx, m = mat[j];
@@ -119,10 +120,28 @@ function tubeIntake(i, p, dx, dy) {
if (PH[m] !== PH_POWDER) continue; // the screw only takes loose material; liquids just flow through
if (stamp[i] === tickStamp) return;
const pj = part[j];
if (pj >= P_TU && pj <= P_TR) continue; // other tube cells move their own contents
if (IS_TUBE[pj]) 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);
if (diagonal) tubeSpread(i, x, y, 0, (y & 3) < 2 ? 1 : -1, true);
else if (ox !== -dx || oy !== -dy) tubeSpread(i, x, y, -ox, -oy, true);
return;
}
}
// Four lanes cross a block in four beats; the casing carries every lane across the corner.
// Prefer the next diagonal block, then either straight join, then the open head.
function diagonalTubeNext(i, p) {
const x = i % W, y = (i / W) | 0, dx = TDX[p], dy = TDY[p];
const xx = x + dx, bx = x & ~3, by = y & ~3;
if (xx < 0 || xx >= W) return -1;
if ((xx >> 2) === (x >> 2)) return i + dx;
const yy = y + dy * BS;
if (yy >= 0 && yy < H && IS_TUBE[part[yy * W + xx]]) return yy * W + xx;
if (IS_TUBE[part[y * W + xx]]) return y * W + xx;
if (dy > 0 && yy < H && (mat[yy * W + xx] === BELTL || mat[yy * W + xx] === BELTR)) return ((yy & ~3) - 1) * W + xx;
const hy = by + (dy > 0 ? BS : -1), hx = bx + (y & 3);
if (hy >= 0 && hy < H && IS_TUBE[part[hy * W + hx]]) return hy * W + hx;
// An open mouth discharges along the diagonal, clear of the last block.
return yy >= 0 && yy < H ? yy * W + xx : -1;
}