Replaces the stub with the real sim per lanes/LANE-SIM.md round 1. - grid + placement/remove/rotate/setRecipe, footprint rotation, bounds - belts: 2 items/tile, 0.45 spacing enforced across the tile seam, back-pressure, merges, belt<->machine handoff - crafting: recipe buffers (2x in, stall at 4x out), edge-triggered jams - bandwidth v1: gen vs draw, compression generates, brownout = gen/draw scaling both craft progress and belt movement - shipping + commission tracking - output routing ranks belts by tracing the chain to its terminal machine, so the demuxer's three outputs reach three different consumers without splitters (see NOTES - biggest judgement call of the round) 18 tests. Measured 3,500 entities + 6,820 belt items at 0.42ms/tick (80x realtime). Full M1 chain ships MELT at tick 1149 in both node and browser. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
27 lines
879 B
TypeScript
27 lines
879 B
TypeScript
/** Grid math. Origin at world center, +x east, +y south, Dir 0..3 = N,E,S,W clockwise. */
|
|
import type { Dir, Vec2 } from '../contracts';
|
|
|
|
export const DIR_VEC: ReadonlyArray<Vec2> = [
|
|
{ x: 0, y: -1 }, // 0 N
|
|
{ x: 1, y: 0 }, // 1 E
|
|
{ x: 0, y: 1 }, // 2 S
|
|
{ x: -1, y: 0 }, // 3 W
|
|
];
|
|
|
|
export const GRID_MIN = -32;
|
|
export const GRID_MAX = 31;
|
|
|
|
/** Packs a tile into a unique number so occupancy can live in a flat Map. */
|
|
export function tileKey(x: number, y: number): number {
|
|
return (x + 32768) * 65536 + (y + 32768);
|
|
}
|
|
|
|
export function inBounds(x: number, y: number): boolean {
|
|
return x >= GRID_MIN && x <= GRID_MAX && y >= GRID_MIN && y <= GRID_MAX;
|
|
}
|
|
|
|
/** Footprint after rotation — facing E or W swaps width and height. */
|
|
export function footprintOf(fp: Vec2, dir: Dir): Vec2 {
|
|
return dir === 1 || dir === 3 ? { x: fp.y, y: fp.x } : { x: fp.x, y: fp.y };
|
|
}
|