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
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);
|
|
}
|