// The build plan and direct variant queries share one direction/material rule. const { load, suite, flatWorld } = require('./harness'); const fs = require('fs'); const { run } = load(), { check, done } = suite(); flatWorld(run, 256, 224, 208); run(fs.readFileSync('src/ui/selection.js', 'utf8')); run(fs.readFileSync('src/ui/actions.js', 'utf8')); run(`globalThis.GAME = { pieceDir: {}, pieceShape: {}, wallMat: RSTONE }; globalThis.aimBlock = () => ({ bx: 20, by: 20 });`); for (const id of ['wall', 'belt', 'filter', 'screw', 'gate', 'pump']) { const dirs = run(`PIECE_BY_ID.${id}.dirs?.length || 1`); for (let dir = 0; dir < dirs; dir++) { run(`GAME.pieceDir.${id} = ${(dir + 1) % dirs};`); const expected = id === 'wall' ? run('RSTONE') : id === 'filter' ? dir << 7 : dir; check(`${id} explicit direction ${dir} gives its stored variant`, run(`pieceV(PIECE_BY_ID.${id}, ${dir})`) === expected); } } for (const id of ['wall', 'belt', 'filter', 'screw', 'gate', 'pump']) { for (const [dx, dy] of [[0, 0], [4, 0], [-4, 0], [0, 4], [0, -4], [4, -4], [4, 4], [-4, 4], [-4, -4]]) { run(`GAME.pieceDir.${id} = 0; GAME.drag = { bx: 20, by: 20 };`); // The endpoint intentionally differs from aimBlock(), including opposite filter slopes. check(`${id} plan ${dx},${dy} keeps the direction and variant rule`, run(`(() => { const P = PIECE_BY_ID.${id}, b = { bx: ${20 + dx}, by: ${20 + dy} }; const plan = dragPlan(P, GAME.drag, b, false); const code = pieceCode(P, b), dd = dragDirFor(P, GAME.drag, b), dir = dd >= 0 ? dd : 0; const expected = isWall(P.code) ? GAME.wallMat : P.filter ? filterVariant(code, dir << 7) : dir; return plan.code === code && plan.dir === dir && plan.v === expected && pieceV(P, dir, code) === expected && [...plan.planned.values()].every(([c, v]) => c === code && v === expected); })()`)); } } done();