2023-06-24 15:24:57 +00:00
|
|
|
import { iter_2d, range } from "./utils/range.mjs";
|
|
|
|
|
2023-06-28 14:16:26 +00:00
|
|
|
const BOX_EXTENT_FROM_CENTER = 4;
|
|
|
|
export const BOX_SIZE = BOX_EXTENT_FROM_CENTER * 2 + 1;
|
|
|
|
export const CENTER = BOX_EXTENT_FROM_CENTER;
|
2023-06-23 09:37:25 +00:00
|
|
|
|
|
|
|
|
2023-06-23 10:05:40 +00:00
|
|
|
|
|
|
|
function create_world (size) {
|
2023-06-24 08:03:32 +00:00
|
|
|
return {
|
2023-06-28 13:04:09 +00:00
|
|
|
tiles: Array(size).fill(0).map(_ =>
|
|
|
|
Array(size).fill(0).map(_ => empty_tile())
|
|
|
|
),
|
2023-06-24 16:51:42 +00:00
|
|
|
depth: 0,
|
2023-06-24 08:03:32 +00:00
|
|
|
};
|
2023-06-23 10:05:40 +00:00
|
|
|
}
|
|
|
|
const world = create_world(BOX_SIZE);
|
2023-06-23 09:37:25 +00:00
|
|
|
|
2023-06-28 13:04:09 +00:00
|
|
|
export function empty_tile () {
|
|
|
|
return { type: "empty" };
|
|
|
|
}
|
|
|
|
|
2023-06-24 15:38:04 +00:00
|
|
|
export function create_new () {
|
|
|
|
return create_world(BOX_SIZE);
|
|
|
|
}
|
|
|
|
|
2023-06-24 08:03:32 +00:00
|
|
|
export function set_tile (world, x, y, tile) {
|
2023-06-24 10:46:52 +00:00
|
|
|
if (out_of_bounds(x, y)) return;
|
2023-06-24 08:03:32 +00:00
|
|
|
world.tiles[x][y] = tile;
|
2023-06-23 09:37:25 +00:00
|
|
|
}
|
|
|
|
|
2023-06-24 08:03:32 +00:00
|
|
|
export function get_tile (world, x, y) {
|
2023-06-24 10:46:52 +00:00
|
|
|
if (out_of_bounds(x, y)) return { type: "out_of_bounds" };
|
2023-06-24 08:03:32 +00:00
|
|
|
return world.tiles[x][y];
|
2023-06-23 10:05:40 +00:00
|
|
|
}
|
|
|
|
|
2023-06-28 13:08:03 +00:00
|
|
|
export function clear_tile (box, x, y) {
|
|
|
|
set_tile(box, x, y, empty_tile());
|
|
|
|
}
|
|
|
|
|
2023-06-24 08:03:32 +00:00
|
|
|
export function create_box (parent) {
|
|
|
|
return {
|
|
|
|
...create_world(BOX_SIZE),
|
2023-06-24 16:51:42 +00:00
|
|
|
depth: parent.depth + 1,
|
2023-06-24 08:03:32 +00:00
|
|
|
parent,
|
|
|
|
};
|
2023-06-23 10:05:40 +00:00
|
|
|
}
|
|
|
|
|
2023-06-24 07:52:53 +00:00
|
|
|
export function get_root () {
|
|
|
|
return world;
|
|
|
|
}
|
2023-06-24 10:46:52 +00:00
|
|
|
|
|
|
|
export function out_of_bounds (x, y) {
|
|
|
|
return x < 0 || x >= BOX_SIZE ||
|
|
|
|
y < 0 || y >= BOX_SIZE
|
|
|
|
}
|
2023-06-24 15:24:57 +00:00
|
|
|
|
2023-06-24 15:50:58 +00:00
|
|
|
export function for_each_tile (world, callback) {
|
|
|
|
iter_2d(range(0, BOX_SIZE - 1), (x, y) => {
|
|
|
|
callback(x, y, get_tile(world, x, y), world);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-06-24 15:24:57 +00:00
|
|
|
export function replace_root (new_world) {
|
|
|
|
// maybe unnecessary to go over each tile instead of just each column.
|
2023-06-24 15:50:58 +00:00
|
|
|
for_each_tile(new_world, (x, y, tile) => {
|
|
|
|
set_tile(world, x, y, tile);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function to_json () {
|
|
|
|
return JSON.stringify(world, (key, value) => {
|
|
|
|
if (key === "parent") return undefined;
|
|
|
|
return value;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function reconstruct_parent (world, parent) {
|
2023-06-24 16:10:58 +00:00
|
|
|
world.parent = parent;
|
2023-06-24 15:50:58 +00:00
|
|
|
for_each_tile(world, (x, y, tile) => {
|
|
|
|
if (tile.type !== "box") return;
|
|
|
|
reconstruct_parent(tile.box, world);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function from_json (json) {
|
2023-06-28 13:04:09 +00:00
|
|
|
const result = JSON.parse(json, (key, value) => {
|
|
|
|
if (value === undefined || value === 0 || value === null) return empty_tile();
|
|
|
|
return value;
|
|
|
|
});
|
2023-06-24 16:10:58 +00:00
|
|
|
|
2023-06-24 15:50:58 +00:00
|
|
|
for_each_tile(result, (x, y, tile) => {
|
2023-06-24 16:10:58 +00:00
|
|
|
if (tile.type === "box") {
|
|
|
|
reconstruct_parent(tile.box, result);
|
|
|
|
}
|
2023-06-24 15:24:57 +00:00
|
|
|
});
|
2023-06-24 16:10:58 +00:00
|
|
|
|
2023-06-24 15:50:58 +00:00
|
|
|
return result;
|
2023-06-24 15:24:57 +00:00
|
|
|
}
|