You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
6.3 KiB

import { StateBuffer } from "./state.js";
export function update(
source: StateBuffer,
target: StateBuffer,
generation: number
) {
const width = source.width;
const height = source.height;
target.fill(0);
let swapped: [number, number][] = [];
// First pass: fall trivial cells
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const cell = source.get(x, y);
if (cell > 0) {
if (source.get(x, y + 1) === 0) {
target.set(x, y + 1, 2);
swapped.push([x, y]);
} else {
target.set(x, y, 1);
}
}
}
}
// Second pass: try to move down cells using swapped
while (swapped.length > 0) {
const [x, y] = swapped.shift()!;
if (target.get(x, y - 1) === 1) {
target.set(x, y, 2);
target.set(x, y - 1, 0);
swapped.push([x, y - 1]);
}
}
// Third pass: mark stuck cells
const CANNOT_MOVE = [2, -1];
for (let y = height; y >= 0; y--) {
for (let x = 0; x < width; x++) {
if (
target.get(x, y) === 1
&& CANNOT_MOVE.includes(target.get(x, y + 1))
&& CANNOT_MOVE.includes(target.get(x + 1, y + 1))
&& CANNOT_MOVE.includes(target.get(x - 1, y + 1))
) {
target.set(x, y, 2);
}
}
}
// Fourth pass: try to move cells diagonally
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
if (
target.get(x, y) === 1 && target.get(x, y + 1) === 2
|| target.get(x, y) === 1 && target.get(x, y + 1) === 1 && target.get(x, y + 2) === 2
) {
const left = target.get(x - 1, y + 1) === 0;
const right = target.get(x + 1, y + 1) === 0;
if (left && right && Math.random() < 0.5 || left && !right) {
target.set(x - 1, y + 1, 2);
target.set(x, y, 0);
swapped.push([x, y]);
} else if (right) {
target.set(x + 1, y + 1, 2);
target.set(x, y, 0);
swapped.push([x, y]);
}
}
}
}
// Fifth pass: try to move remaining cells to free spots
while (swapped.length > 0) {
const [x, y] = swapped.shift()!;
if (target.get(x, y - 1) === 1) {
target.set(x, y, 2);
target.set(x, y - 1, 0);
swapped.push([x, y - 1]);
} else if (target.get(x - 1, y - 1) === 1) {
target.set(x, y, 2);
target.set(x - 1, y - 1, 0);
swapped.push([x - 1, y - 1]);
} else if (target.get(x + 1, y - 1) === 1) {
target.set(x, y, 2);
target.set(x + 1, y - 1, 0);
swapped.push([x + 1, y - 1]);
}
}
// Sixth pass: convert 2 -> 1
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
if (target.get(x, y) === 2) {
target.set(x, y, 1);
}
}
}
// Second pass: look for cells that could slot into swapped cells
// do {
// while (swapped.length > 0) {
// const [x, y] = swapped.shift()!;
// if (target.get(x, y - 1) === 1) {
// target.set(x, y, 2);
// target.set(x, y - 1, 0);
// swapped.push([x, y - 1]);
// } else if (target.get(x - 1, y - 1) === 1) {
// if (target.get(x - 1, y) === 0) {
// target.set(x - 1, y, 2);
// target.set(x - 1, y - 1, 0);
// swapped = swapped.filter(([x2, y2]) => x2 !== x - 1 || y2 !== y);
// swapped.push([x - 1, y - 1]);
// } else if (target.get(x + 2, y) === 0 && Math.random() < 0.5) {
// target.set(x + 2, y, 2);
// target.set(x - 1, y - 1, 0);
// swapped = swapped.filter(([x2, y2]) => x2 !== x - 2 || y2 !== y);
// swapped.push([x, y]);
// swapped.push([x - 1, y - 1]);
// } else {
// target.set(x, y, 2);
// target.set(x - 1, y - 1, 0);
// swapped.push([x - 1, y - 1]);
// }
// } else if (target.get(x + 1, y - 1) === 1) {
// if (target.get(x + 1, y) === 0) {
// target.set(x + 1, y, 2);
// target.set(x + 1, y - 1, 0);
// swapped = swapped.filter(([x2, y2]) => x2 !== x + 1 || y2 !== y);
// swapped.push([x + 1, y - 1]);
// } else if (target.get(x - 2, y) === 0 && Math.random() < 0.5) {
// target.set(x - 2, y, 2);
// target.set(x + 1, y - 1, 0);
// swapped = swapped.filter(([x2, y2]) => x2 !== x - 2 || y2 !== y);
// swapped.push([x, y]);
// swapped.push([x + 1, y - 1]);
// } else {
// target.set(x, y, 2);
// target.set(x + 1, y - 1, 0);
// swapped.push([x + 1, y - 1]);
// }
// }
// }
// // Third pass: apply the diagonal movement rule to any unmoved cell
// for (let y = 0; y < height; y++) {
// for (let x = 0; x < width; x++) {
// if (target.get(x, y) === 1 && target.get(x, y + 1) > 0) {
// const left = target.get(x - 1, y + 1) === 0;
// const right = target.get(x + 1, y + 1) === 0;
// if (left && right && Math.random() < 0.5 || left && !right) {
// target.set(x - 1, y + 1, 2);
// target.set(x, y, 0);
// swapped.push([x, y]);
// } else if (right) {
// target.set(x + 1, y + 1, 2);
// target.set(x, y, 0);
// swapped.push([x, y]);
// }
// }
// }
// }
// } while (swapped.length > 0);
}