cave = {
let grid = new Array(Y_MAX).fill(0).map(() => new Array(X_MAX).fill(0));
let spliced = 0;
let highest = new Array(X_MAX).fill(-1);
let cycle = { step: -1, nb: 0, shapes: new Map() };
for (let round = 0; round < 1740 * X + 1180; round++) {
let s = SHAPES[round % SHAPES.length];
let h_max = highest.reduce((a,b) => Math.max(a,b), -1);
let px = 2;
let py = h_max + 4;
let stopped = false;
while (!stopped) {
cycle.step = (cycle.step + 1) % MOVEMENTS.length;
if (cycle.step === 0) {
cycle.nb++;
let h_min = highest.reduce((a,b) => Math.min(a,b), highest[0]);
let fingerprint = `${round % SHAPES.length}:${py - h_max}/${py - h_min}:${highest.map(n => n - h_min)}`;
if (!cycle.shapes.has(fingerprint)) {
cycle.shapes.set(fingerprint, []);
}
cycle.shapes.set(fingerprint, [h_min+spliced, ...cycle.shapes.get(fingerprint)]);
}
let m = MOVEMENTS[cycle.step] === ">" ? 1 : -1;
if (allowed(grid, s, px + m, py)) {
px += m;
}
if (allowed(grid, s, px, py - 1)) {
py = py - 1;
} else {
stopped = true;
}
}
for (let j = 0; j < s.length; j++) {
for (let i = 0; i < s[j].length; i++) {
grid[j+py][i+px] += s[j][i];
if (s[j][i] > 0 && highest[i+px] < j+py) {
highest[i+px] = j+py
}
}
}
if (round % 100000 === 0) {
let min = highest.reduce((a,b) => Math.min(a,b), highest[0]);
if (min > 0) {
grid = new Array(Y_MAX).fill(0).map((_, i) => i+min < Y_MAX ? grid[i+min] : new Array(X_MAX).fill(0));
spliced += min;
highest = highest.map(n => n - min);
}
}
}
return [grid, highest, spliced, cycle];
}