summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--aoc_2022/day-09/example.test.ts33
-rw-r--r--aoc_2022/day-09/logs/.gitkeep (renamed from aoc_2022/day-09/.gitkeep)0
-rw-r--r--aoc_2022/day-09/logs/out_1.txt7
-rw-r--r--aoc_2022/day-09/logs/out_2.txt7
-rw-r--r--aoc_2022/day-09/part_1.ts75
-rw-r--r--aoc_2022/day-09/part_2.ts61
-rw-r--r--aoc_2022/day-09/problem.txt2000
-rw-r--r--tsconfig.json5
-rw-r--r--utils/index.ts2
-rw-r--r--utils/jsonds.ts66
-rw-r--r--utils/point2d.ts9
11 files changed, 2264 insertions, 1 deletions
diff --git a/aoc_2022/day-09/example.test.ts b/aoc_2022/day-09/example.test.ts
new file mode 100644
index 0000000..8fea0c3
--- /dev/null
+++ b/aoc_2022/day-09/example.test.ts
@@ -0,0 +1,33 @@
+import { expect, test } from "bun:test";
+import { main as part1 } from "./part_1";
+import { main as part2 } from "./part_2";
+
+const example = `R 4
+U 4
+L 3
+D 1
+R 4
+D 1
+L 5
+R 2`.split("\n");
+const example2 = `R 5
+U 8
+L 8
+D 3
+R 17
+D 10
+L 25
+U 20`.split("\n");
+//const example = `1 2 3 4 5`.split(" ");
+
+test("part1", async () => {
+ const answer = 13;
+ const res = await part1(example);
+ expect(res).toEqual(answer);
+});
+
+test("part2", async () => {
+ const answer = 36;
+ const res = await part2(example2);
+ expect(res).toEqual(answer);
+});
diff --git a/aoc_2022/day-09/.gitkeep b/aoc_2022/day-09/logs/.gitkeep
index e69de29..e69de29 100644
--- a/aoc_2022/day-09/.gitkeep
+++ b/aoc_2022/day-09/logs/.gitkeep
diff --git a/aoc_2022/day-09/logs/out_1.txt b/aoc_2022/day-09/logs/out_1.txt
new file mode 100644
index 0000000..38b65db
--- /dev/null
+++ b/aoc_2022/day-09/logs/out_1.txt
@@ -0,0 +1,7 @@
+=== COMPUTATION ===
+
+
+=== /COMPUTATION ===
+
+=== ANSWER TO P1 ===
+6269
diff --git a/aoc_2022/day-09/logs/out_2.txt b/aoc_2022/day-09/logs/out_2.txt
new file mode 100644
index 0000000..419b4ad
--- /dev/null
+++ b/aoc_2022/day-09/logs/out_2.txt
@@ -0,0 +1,7 @@
+=== COMPUTATION ===
+
+
+=== /COMPUTATION ===
+
+=== ANSWER TO P2 ===
+2557
diff --git a/aoc_2022/day-09/part_1.ts b/aoc_2022/day-09/part_1.ts
new file mode 100644
index 0000000..b255aca
--- /dev/null
+++ b/aoc_2022/day-09/part_1.ts
@@ -0,0 +1,75 @@
+import { JSONSet } from "@/utils";
+
+type Point = {
+ x: number;
+ y: number;
+};
+
+const distance = (p1: Point, p2: Point) =>
+ Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
+
+const isDiagAdj = (p1: Point, p2: Point) => distance(p1, p2) <= Math.sqrt(2);
+
+export const main = async (lines: string[]): Promise<number | string> => {
+ const knots: Point[] = Array(2)
+ .fill(null)
+ .map(() => ({ x: 0, y: 0 }));
+
+ const visited: JSONSet<Point> = new JSONSet();
+ visited.add(knots[0]);
+
+ for (const step of lines) {
+ const [dir, steps_s] = step.split(" ");
+ const steps = parseInt(steps_s);
+
+ for (let i = 0; i < steps; ++i) {
+ if (dir === "U") knots[0].y += 1;
+ if (dir === "L") knots[0].x -= 1;
+ if (dir === "R") knots[0].x += 1;
+ if (dir === "D") knots[0].y -= 1;
+
+ for (let knotidx = 1; knotidx < knots.length; knotidx++) {
+ const [head, tail] = [knots[knotidx - 1], knots[knotidx]];
+ if (!isDiagAdj(head, tail)) {
+ if (dir === "U") {
+ tail.x = head.x;
+ tail.y = head.y - 1;
+ }
+ if (dir === "L") {
+ tail.x = head.x + 1;
+ tail.y = head.y;
+ }
+ if (dir === "R") {
+ tail.x = head.x - 1;
+ tail.y = head.y;
+ }
+ if (dir === "D") {
+ tail.x = head.x;
+ tail.y = head.y + 1;
+ }
+ visited.add(tail);
+ }
+ }
+ }
+ }
+
+ return visited.size;
+};
+
+//
+
+const isrun = process.argv.length > 1 && process.argv[1] === import.meta.path;
+if (isrun) {
+ const file = Bun.file("./problem.txt");
+ const text = await file.text();
+ const lines = text.split("\n").filter((x) => x && x.length);
+
+ console.log("=== COMPUTATION ===\n");
+
+ const answer = await main(lines);
+
+ console.log("\n=== /COMPUTATION ===\n");
+
+ console.log("=== ANSWER TO P1 ===");
+ console.log(answer);
+}
diff --git a/aoc_2022/day-09/part_2.ts b/aoc_2022/day-09/part_2.ts
new file mode 100644
index 0000000..5b0df2a
--- /dev/null
+++ b/aoc_2022/day-09/part_2.ts
@@ -0,0 +1,61 @@
+import { JSONSet, Vec2, l2Norm, isDiagAdj } from "@/utils";
+
+export const main = async (lines: string[]): Promise<number | string> => {
+ const knots: Vec2[] = Array(10)
+ .fill(null)
+ .map(() => ({ x: 0, y: 0 }));
+
+ const visited: JSONSet<Vec2> = new JSONSet();
+ visited.add(knots[0]);
+
+ for (const step of lines) {
+ const [dir, steps_s] = step.split(" ");
+ const steps = parseInt(steps_s);
+
+ for (let i = 0; i < steps; ++i) {
+ if (dir === "U") knots[0].y += 1;
+ if (dir === "L") knots[0].x -= 1;
+ if (dir === "R") knots[0].x += 1;
+ if (dir === "D") knots[0].y -= 1;
+
+ for (let knotidx = 1; knotidx < knots.length; knotidx++) {
+ const [head, tail] = [knots[knotidx - 1], knots[knotidx]];
+
+ if (!isDiagAdj(head, tail)) {
+ if (head.y - tail.y === 0) {
+ tail.x += Math.floor((head.x - tail.x) / 2);
+ } else if (head.x - tail.x === 0) {
+ tail.y += Math.floor((head.y - tail.y) / 2);
+ } else {
+ tail.x += head.x - tail.x > 0 ? 1 : -1;
+ tail.y += head.y - tail.y > 0 ? 1 : -1;
+ }
+ }
+
+ if (knotidx === knots.length - 1) {
+ visited.add(tail);
+ }
+ }
+ }
+ }
+
+ return visited.size;
+};
+
+//
+
+const isrun = process.argv.length > 1 && process.argv[1] === import.meta.path;
+if (isrun) {
+ const file = Bun.file("./problem.txt");
+ const text = await file.text();
+ const lines = text.split("\n").filter((x) => x && x.length);
+
+ console.log("=== COMPUTATION ===\n");
+
+ const answer = await main(lines);
+
+ console.log("\n=== /COMPUTATION ===\n");
+
+ console.log("=== ANSWER TO P2 ===");
+ console.log(answer);
+}
diff --git a/aoc_2022/day-09/problem.txt b/aoc_2022/day-09/problem.txt
new file mode 100644
index 0000000..2b57957
--- /dev/null
+++ b/aoc_2022/day-09/problem.txt
@@ -0,0 +1,2000 @@
+L 1
+R 1
+D 1
+R 2
+D 2
+L 1
+D 1
+L 2
+R 1
+L 1
+U 1
+D 2
+R 1
+D 2
+R 1
+L 2
+D 1
+U 1
+L 2
+U 1
+D 1
+U 1
+D 2
+L 2
+D 2
+L 1
+D 2
+R 2
+L 1
+D 2
+R 2
+D 2
+R 1
+L 2
+U 1
+R 2
+U 2
+D 1
+R 2
+U 1
+R 2
+L 2
+U 1
+L 2
+D 2
+L 1
+U 1
+R 2
+U 1
+R 2
+U 1
+R 2
+U 2
+L 1
+U 2
+L 2
+R 2
+L 2
+R 2
+L 1
+D 1
+L 1
+U 1
+R 2
+L 1
+R 2
+L 1
+R 1
+L 2
+R 2
+D 1
+L 2
+R 1
+L 2
+R 1
+D 2
+U 2
+D 1
+R 2
+L 2
+D 2
+U 1
+R 2
+U 2
+D 2
+R 2
+D 1
+R 2
+D 2
+R 1
+D 2
+R 1
+D 2
+U 1
+R 2
+U 2
+R 2
+L 1
+U 2
+L 1
+R 1
+U 1
+R 1
+L 1
+U 1
+D 2
+L 1
+D 2
+U 1
+R 1
+D 2
+U 1
+D 3
+R 1
+L 3
+U 3
+L 2
+U 3
+D 2
+U 2
+D 2
+U 2
+D 1
+L 1
+D 1
+U 1
+D 2
+U 2
+R 3
+D 1
+L 1
+D 1
+R 1
+U 2
+R 2
+D 2
+R 2
+U 2
+R 2
+L 3
+R 2
+D 1
+R 3
+U 1
+L 3
+U 3
+L 2
+R 3
+D 2
+L 3
+D 1
+L 2
+U 3
+L 2
+U 3
+D 2
+L 3
+R 3
+U 3
+D 2
+U 3
+D 3
+U 2
+D 2
+U 2
+D 3
+L 1
+R 2
+U 1
+L 1
+R 1
+U 1
+D 2
+R 2
+U 3
+L 1
+D 2
+R 3
+D 1
+U 2
+R 1
+L 2
+R 2
+U 2
+R 2
+D 1
+L 3
+U 3
+L 2
+D 1
+U 3
+R 3
+D 1
+U 3
+L 1
+D 2
+U 1
+D 1
+L 3
+R 1
+L 1
+U 3
+L 2
+U 1
+R 1
+U 3
+L 2
+U 1
+L 2
+D 2
+L 2
+U 3
+D 2
+L 1
+U 3
+L 2
+U 2
+D 3
+L 3
+U 1
+D 2
+R 2
+D 1
+U 3
+R 4
+U 2
+D 2
+L 2
+U 2
+L 1
+R 2
+D 2
+U 1
+D 2
+R 1
+U 4
+R 1
+U 2
+D 2
+U 2
+D 1
+L 1
+R 2
+D 3
+U 1
+D 3
+R 2
+L 4
+U 4
+L 4
+U 3
+D 1
+R 2
+L 3
+D 4
+U 3
+D 3
+U 2
+D 2
+U 2
+D 1
+U 3
+D 1
+L 4
+U 2
+L 2
+U 1
+R 1
+L 3
+R 4
+L 1
+U 1
+L 1
+D 1
+L 2
+U 4
+R 1
+D 3
+U 3
+L 1
+U 1
+D 4
+L 1
+D 3
+U 2
+L 4
+U 2
+R 2
+U 1
+R 1
+L 3
+R 1
+D 4
+U 3
+L 1
+U 2
+L 1
+D 3
+R 3
+U 4
+R 4
+D 4
+L 3
+U 4
+L 3
+D 2
+R 2
+D 3
+U 1
+D 1
+R 2
+D 2
+L 2
+R 2
+D 4
+U 4
+L 2
+D 3
+L 4
+R 2
+U 1
+D 4
+L 2
+D 1
+U 3
+L 2
+R 4
+U 1
+R 2
+U 3
+L 3
+D 4
+R 2
+L 2
+D 4
+U 1
+R 3
+U 3
+D 5
+L 4
+D 3
+U 4
+R 5
+L 3
+R 1
+D 1
+R 4
+L 1
+D 5
+L 4
+R 2
+U 1
+D 2
+R 4
+U 5
+R 4
+D 2
+R 4
+D 4
+R 2
+L 4
+R 4
+U 2
+D 1
+L 4
+R 4
+U 3
+D 2
+L 5
+R 4
+L 2
+R 2
+D 3
+U 3
+D 3
+L 4
+D 2
+U 2
+L 4
+R 1
+D 2
+L 4
+U 2
+L 4
+U 2
+D 2
+L 2
+R 4
+D 4
+U 3
+L 1
+R 4
+L 4
+R 5
+D 2
+R 2
+U 1
+D 4
+L 2
+U 3
+R 1
+L 3
+R 4
+L 2
+R 3
+U 1
+R 5
+U 2
+L 4
+R 2
+D 4
+U 3
+R 2
+L 4
+D 4
+U 4
+D 2
+U 5
+L 5
+U 1
+D 5
+L 1
+R 1
+L 2
+D 2
+U 1
+R 3
+U 3
+L 3
+D 1
+R 5
+D 5
+L 3
+R 3
+D 2
+L 1
+D 2
+L 3
+U 1
+R 5
+U 2
+R 3
+L 2
+U 1
+D 4
+L 1
+D 2
+U 4
+D 3
+U 6
+L 3
+D 4
+R 6
+U 4
+L 3
+D 2
+L 1
+U 1
+D 6
+R 4
+L 1
+D 4
+L 3
+U 2
+L 2
+R 2
+L 1
+D 2
+U 2
+L 5
+U 6
+L 1
+D 3
+U 1
+L 1
+U 6
+D 4
+R 6
+D 2
+R 3
+L 2
+D 3
+U 1
+D 4
+U 1
+D 4
+R 3
+L 3
+R 2
+L 1
+R 6
+L 5
+R 3
+D 2
+L 6
+R 4
+D 1
+R 4
+L 6
+R 1
+U 5
+D 2
+U 4
+R 6
+D 5
+U 5
+R 6
+L 5
+D 4
+U 3
+L 6
+U 3
+R 5
+U 1
+L 6
+D 1
+U 6
+L 1
+R 4
+L 3
+R 6
+D 2
+L 1
+U 4
+D 4
+L 1
+U 6
+L 6
+U 5
+L 6
+R 5
+L 5
+R 2
+U 6
+R 1
+U 2
+D 6
+U 3
+D 4
+U 4
+L 6
+U 6
+R 4
+D 5
+L 2
+D 5
+R 1
+L 2
+D 6
+U 6
+L 6
+U 1
+R 4
+L 5
+D 6
+L 6
+U 7
+D 4
+L 4
+R 2
+U 5
+L 7
+R 3
+D 6
+R 1
+L 2
+R 2
+U 5
+R 5
+D 3
+L 4
+U 2
+L 6
+R 2
+U 3
+D 2
+R 7
+L 3
+D 6
+L 4
+R 1
+D 7
+R 4
+U 3
+L 4
+D 5
+L 4
+D 2
+L 5
+U 4
+R 6
+D 2
+L 4
+U 4
+L 3
+R 7
+L 6
+U 1
+D 5
+L 6
+D 3
+L 7
+D 5
+L 1
+R 1
+D 7
+U 6
+L 4
+D 6
+U 7
+L 7
+D 6
+L 4
+R 4
+U 5
+D 4
+U 2
+R 4
+U 4
+L 2
+D 6
+U 6
+L 5
+R 7
+L 4
+R 7
+L 4
+U 5
+D 3
+L 6
+R 1
+D 2
+U 4
+L 3
+D 1
+R 2
+U 2
+D 4
+L 6
+U 7
+D 1
+R 1
+L 4
+R 1
+D 6
+U 6
+R 2
+D 7
+R 2
+D 2
+U 3
+L 5
+U 5
+L 4
+D 2
+R 2
+U 5
+R 1
+D 7
+L 6
+D 1
+R 1
+L 2
+D 3
+R 7
+L 2
+U 2
+D 4
+R 6
+U 2
+R 4
+U 2
+R 1
+L 3
+R 7
+U 2
+R 7
+L 4
+U 4
+R 4
+L 4
+D 3
+U 1
+L 5
+D 8
+L 7
+R 7
+D 2
+U 1
+L 5
+R 5
+L 2
+D 1
+U 6
+R 3
+U 2
+R 7
+L 7
+U 7
+D 3
+R 6
+U 2
+L 7
+U 7
+R 4
+D 6
+R 4
+U 4
+D 4
+R 1
+U 4
+R 1
+U 2
+D 6
+L 2
+D 1
+L 6
+D 2
+U 3
+D 4
+U 8
+R 5
+U 8
+R 1
+D 7
+L 5
+U 4
+D 2
+U 6
+D 4
+L 8
+D 5
+R 1
+U 6
+L 8
+R 7
+D 1
+U 5
+D 8
+R 3
+U 3
+D 2
+L 3
+U 3
+R 4
+D 7
+U 2
+D 2
+L 4
+R 6
+L 6
+D 2
+R 5
+D 4
+U 7
+D 6
+U 3
+L 8
+D 3
+R 7
+U 3
+R 5
+D 1
+U 6
+D 8
+L 7
+D 5
+L 6
+R 5
+L 4
+R 7
+L 8
+D 5
+U 5
+R 8
+L 6
+D 7
+R 9
+U 7
+L 8
+D 6
+U 2
+D 2
+R 9
+D 2
+L 5
+R 3
+U 6
+R 6
+L 7
+R 5
+D 3
+R 7
+D 1
+L 1
+U 5
+D 2
+R 6
+D 4
+R 2
+U 1
+L 9
+D 8
+R 2
+U 3
+D 6
+L 3
+D 3
+R 5
+L 1
+U 5
+L 6
+R 4
+L 4
+U 3
+L 6
+D 5
+L 9
+D 7
+R 9
+U 1
+R 7
+U 2
+D 8
+L 6
+U 1
+L 2
+U 3
+D 1
+L 3
+U 7
+L 3
+R 3
+D 2
+L 4
+U 3
+R 6
+L 5
+R 3
+U 5
+R 6
+L 7
+D 8
+L 8
+D 6
+U 4
+R 5
+U 2
+D 9
+L 1
+R 1
+D 9
+U 2
+L 8
+U 1
+L 3
+D 2
+L 6
+U 7
+D 7
+U 9
+R 1
+D 1
+U 4
+L 1
+U 5
+L 7
+U 2
+D 4
+U 3
+R 6
+D 3
+L 9
+D 5
+U 3
+D 1
+L 4
+U 2
+R 6
+L 1
+R 6
+D 1
+L 3
+U 8
+R 2
+U 9
+D 3
+L 8
+R 5
+U 6
+R 8
+L 2
+D 5
+L 1
+U 7
+R 1
+L 7
+D 2
+R 8
+U 5
+D 5
+L 9
+D 6
+R 10
+D 3
+R 2
+D 6
+L 7
+D 8
+R 1
+D 4
+R 9
+L 5
+D 7
+U 2
+R 3
+L 4
+D 7
+U 5
+D 5
+L 9
+U 6
+D 7
+U 5
+D 8
+R 3
+U 3
+D 3
+R 10
+D 2
+U 7
+D 2
+U 2
+R 2
+U 8
+L 9
+U 5
+D 1
+U 5
+D 8
+R 4
+D 2
+R 1
+U 9
+L 2
+D 9
+R 5
+L 10
+R 1
+U 2
+L 3
+D 8
+U 8
+L 3
+U 4
+R 2
+L 6
+R 10
+D 5
+U 6
+L 10
+D 3
+U 2
+L 2
+R 9
+U 5
+R 2
+L 3
+R 4
+L 1
+D 4
+L 8
+R 3
+D 4
+U 5
+R 8
+D 3
+L 5
+D 1
+U 8
+R 4
+U 4
+L 9
+R 3
+L 10
+D 1
+L 10
+D 7
+L 3
+R 8
+L 7
+R 8
+D 4
+R 5
+U 2
+D 6
+U 4
+D 4
+U 9
+L 6
+D 3
+R 9
+U 2
+R 9
+U 10
+R 1
+D 5
+L 9
+R 1
+U 5
+R 3
+D 7
+U 5
+D 7
+L 7
+D 9
+R 11
+D 2
+R 5
+U 1
+D 5
+U 4
+R 6
+L 10
+D 2
+R 2
+U 4
+L 2
+R 7
+U 11
+R 5
+D 9
+L 4
+D 11
+U 8
+L 8
+D 10
+R 4
+L 5
+D 5
+L 1
+D 3
+L 6
+U 9
+D 11
+R 10
+D 6
+R 10
+U 4
+L 1
+U 1
+R 7
+D 6
+R 6
+D 5
+U 11
+R 8
+D 7
+U 10
+L 4
+U 8
+R 11
+L 4
+R 9
+D 3
+L 10
+U 9
+L 8
+U 3
+D 3
+R 1
+L 11
+U 1
+D 7
+L 7
+D 8
+L 11
+D 6
+L 7
+U 6
+D 11
+R 9
+U 11
+L 9
+U 2
+D 1
+L 1
+D 2
+L 6
+R 4
+D 7
+U 8
+R 11
+D 9
+L 8
+D 7
+U 3
+R 7
+D 11
+L 3
+U 5
+L 3
+D 6
+U 2
+L 1
+R 2
+D 7
+R 10
+L 1
+U 1
+R 8
+D 5
+R 3
+L 3
+D 7
+R 10
+U 1
+R 8
+L 7
+U 5
+R 2
+U 10
+L 6
+R 8
+D 1
+U 12
+R 3
+L 6
+D 2
+R 12
+L 5
+R 8
+D 12
+R 8
+D 4
+R 3
+U 10
+D 8
+R 7
+U 3
+D 8
+U 5
+L 12
+U 10
+D 6
+R 5
+L 3
+R 8
+U 2
+R 5
+L 3
+U 7
+R 2
+L 4
+U 12
+R 6
+L 1
+U 3
+L 4
+U 6
+R 7
+U 12
+L 5
+R 8
+D 1
+U 5
+L 10
+D 8
+R 5
+L 10
+D 1
+R 5
+D 8
+U 2
+L 8
+D 11
+R 4
+U 11
+D 10
+U 9
+D 8
+R 9
+U 10
+D 12
+L 3
+D 1
+U 11
+R 10
+L 6
+R 4
+U 3
+R 4
+L 1
+U 12
+D 10
+L 1
+R 9
+L 3
+D 10
+L 12
+U 4
+D 6
+R 5
+U 11
+D 5
+L 8
+R 9
+L 4
+R 11
+D 6
+L 1
+U 10
+R 7
+U 4
+D 2
+L 3
+R 12
+U 7
+D 7
+U 2
+L 11
+R 8
+U 4
+R 1
+U 13
+L 8
+R 2
+D 6
+U 2
+R 2
+U 2
+L 6
+U 7
+D 6
+R 7
+D 7
+L 3
+R 5
+L 1
+U 9
+R 7
+U 4
+L 7
+D 9
+L 10
+R 13
+L 11
+D 8
+R 10
+L 12
+U 12
+R 5
+U 3
+L 1
+R 10
+D 13
+L 1
+R 9
+L 3
+U 11
+L 1
+D 4
+L 1
+R 7
+D 12
+R 11
+U 5
+D 12
+L 5
+D 7
+R 7
+L 12
+U 8
+D 7
+U 5
+R 13
+L 10
+R 7
+D 4
+U 8
+L 10
+R 8
+L 6
+R 5
+D 13
+L 7
+U 8
+D 12
+R 10
+L 4
+D 7
+U 4
+L 11
+R 3
+L 6
+R 6
+D 3
+R 11
+L 10
+R 8
+U 5
+R 4
+U 5
+R 10
+L 4
+D 3
+U 8
+R 11
+D 12
+R 9
+L 11
+R 9
+L 9
+R 5
+U 13
+R 2
+U 4
+D 12
+R 9
+L 10
+D 4
+L 2
+D 13
+L 3
+D 11
+U 10
+D 10
+U 13
+L 2
+U 1
+L 9
+U 10
+L 12
+U 14
+R 8
+U 10
+D 6
+R 13
+D 10
+L 6
+U 3
+R 8
+L 1
+R 2
+D 14
+U 11
+L 4
+D 11
+R 14
+U 7
+R 1
+D 5
+U 12
+R 8
+D 11
+R 14
+U 3
+R 8
+U 5
+L 13
+D 5
+L 8
+R 1
+L 12
+D 5
+R 8
+L 4
+D 1
+R 6
+L 14
+R 1
+U 11
+R 4
+D 12
+L 10
+R 7
+D 4
+U 1
+L 3
+U 13
+R 1
+D 13
+U 2
+R 9
+D 1
+L 5
+R 8
+U 2
+D 9
+L 5
+D 4
+L 3
+D 11
+L 3
+R 14
+D 9
+R 2
+U 3
+D 10
+L 4
+D 14
+L 12
+R 5
+D 14
+L 3
+U 1
+D 13
+U 6
+R 3
+L 9
+R 7
+U 8
+R 9
+D 9
+U 8
+D 3
+R 4
+D 5
+U 14
+L 5
+D 12
+L 1
+R 3
+D 6
+R 10
+U 5
+R 4
+D 3
+L 12
+D 13
+L 13
+D 8
+L 3
+D 13
+L 1
+R 9
+D 2
+L 5
+U 13
+R 3
+D 14
+R 8
+L 3
+U 10
+L 6
+R 2
+L 1
+U 15
+R 2
+D 11
+R 3
+L 11
+D 13
+L 5
+D 2
+U 11
+L 5
+D 6
+U 3
+R 7
+U 14
+R 9
+D 5
+R 2
+L 15
+U 13
+D 14
+L 14
+U 8
+L 14
+D 15
+R 7
+U 6
+D 3
+U 7
+D 10
+L 4
+R 8
+L 13
+U 10
+D 2
+U 7
+D 14
+R 2
+L 6
+R 13
+L 6
+D 10
+U 9
+D 14
+U 5
+D 6
+R 4
+L 3
+R 1
+L 3
+D 9
+U 14
+R 2
+D 15
+L 3
+D 11
+L 4
+U 13
+D 14
+U 12
+D 8
+R 11
+U 14
+R 15
+D 8
+L 3
+D 10
+L 10
+U 14
+D 13
+L 7
+D 8
+U 12
+L 3
+D 6
+L 8
+R 1
+L 5
+R 15
+L 1
+D 5
+U 4
+R 11
+L 14
+D 7
+L 9
+U 5
+R 7
+D 4
+R 13
+L 15
+U 5
+L 3
+R 6
+D 13
+L 11
+U 9
+R 6
+D 2
+R 5
+D 11
+R 2
+U 11
+R 14
+L 11
+U 3
+L 4
+R 14
+D 7
+R 10
+U 6
+R 14
+D 8
+R 15
+D 3
+U 9
+L 14
+R 7
+L 14
+R 7
+U 13
+L 12
+U 7
+R 9
+D 7
+L 2
+D 13
+U 8
+D 14
+U 4
+R 7
+L 3
+R 7
+U 7
+R 15
+D 13
+U 4
+L 15
+D 12
+U 11
+L 16
+D 16
+L 12
+U 4
+D 3
+R 11
+U 2
+L 4
+U 6
+R 3
+D 4
+R 1
+D 16
+U 6
+D 7
+L 9
+U 5
+R 3
+L 5
+R 2
+U 3
+L 8
+R 13
+U 10
+D 1
+L 15
+D 1
+R 7
+L 16
+D 5
+U 8
+R 13
+D 11
+L 9
+D 8
+U 6
+R 7
+D 14
+U 9
+L 4
+R 10
+D 14
+R 13
+U 15
+D 9
+R 2
+D 5
+L 10
+U 11
+D 7
+U 11
+D 4
+U 8
+R 13
+U 15
+L 15
+U 12
+L 10
+D 10
+R 16
+D 14
+U 10
+R 16
+D 3
+R 16
+L 13
+D 5
+R 9
+L 9
+R 10
+D 8
+R 11
+D 12
+L 10
+R 15
+L 5
+U 12
+L 3
+U 1
+R 1
+L 6
+R 7
+L 5
+D 4
+L 10
+U 15
+L 10
+U 7
+L 5
+D 3
+L 11
+U 12
+R 16
+L 17
+U 8
+D 2
+L 13
+U 10
+L 2
+R 4
+D 4
+L 14
+D 6
+U 5
+D 14
+U 17
+D 7
+R 3
+D 10
+L 11
+D 15
+L 4
+D 5
+L 7
+D 3
+R 15
+U 10
+R 12
+L 7
+U 13
+R 6
+L 6
+R 4
+L 6
+D 3
+U 9
+D 17
+R 6
+D 1
+R 5
+L 3
+R 6
+L 17
+D 1
+L 6
+U 9
+L 15
+U 10
+R 7
+U 7
+R 15
+U 8
+R 16
+D 16
+L 3
+U 17
+L 16
+D 8
+L 6
+R 1
+D 10
+L 13
+D 17
+U 10
+D 15
+U 12
+D 1
+L 10
+R 8
+D 13
+L 16
+R 1
+U 1
+D 5
+U 1
+L 12
+R 9
+U 7
+L 7
+D 7
+U 15
+R 6
+L 10
+R 17
+D 6
+R 10
+U 10
+D 16
+L 16
+U 14
+R 13
+U 15
+L 7
+U 11
+L 16
+U 9
+L 5
+D 16
+R 8
+U 17
+D 6
+R 18
+D 17
+L 14
+D 13
+R 2
+U 2
+R 5
+U 10
+L 17
+U 4
+L 7
+U 1
+D 14
+R 11
+L 6
+D 5
+U 12
+D 16
+U 5
+D 3
+R 18
+D 12
+R 3
+U 5
+L 1
+U 1
+D 14
+L 8
+R 15
+U 9
+L 10
+D 3
+L 5
+U 11
+D 7
+R 17
+U 7
+D 1
+U 16
+D 15
+L 11
+U 8
+L 5
+R 5
+D 15
+L 5
+U 1
+R 3
+L 7
+U 11
+D 12
+L 12
+D 14
+U 13
+D 14
+R 14
+D 5
+R 12
+D 7
+L 17
+U 18
+D 13
+L 2
+D 3
+R 6
+U 9
+L 1
+R 3
+U 17
+L 7
+D 5
+U 9
+L 2
+D 8
+U 16
+L 3
+U 10
+D 4
+U 6
+D 11
+L 18
+U 11
+L 18
+R 18
+U 3
+R 11
+L 18
+U 14
+D 7
+L 16
+D 2
+L 8
+D 8
+L 9
+R 5
+U 14
+R 15
+D 5
+U 18
+D 5
+L 5
+R 7
+D 4
+R 8
+L 13
+D 15
+R 10
+U 5
+L 1
+D 8
+L 1
+U 6
+L 7
+D 4
+U 12
+R 4
+D 11
+R 5
+L 6
+R 3
+L 1
+D 14
+L 18
+D 5
+U 2
+R 8
+D 18
+R 11
+U 10
+R 4
+U 14
+D 15
+U 17
+R 16
+D 15
+R 8
+U 14
+R 18
+L 2
+R 3
+L 10
+R 9
+U 17
+R 2
+U 19
+L 7
+D 19
+L 8
+R 12
+U 1
+L 18
+R 7
+L 18
+D 19
+U 9
+L 5
+D 5
+L 14
+U 2
+R 8
+D 19
+R 17
+U 6
+D 4
+R 7
+U 6
+R 14
+U 3
+D 17
+U 14
+R 19
+U 1
+R 17
+L 11
+U 18
+L 13
+R 16
+D 9
+L 3
+U 9
+D 5
+L 2
+D 5
+L 10
+U 10
+R 10
+U 6
+D 4
+R 3
+U 1
+L 18
+U 15
+R 2
+L 2
+U 9
+R 2
+U 8
+R 18
+D 16
+R 3
+D 6
+R 14
+L 15
+D 18
+L 12
+R 7
+L 18
+D 15
+R 13
+D 8
+L 8
+R 9
+L 4
+U 11
+R 12
+L 13
+U 12
+D 5
+L 4
+D 19
+R 10
+L 9
+U 18
diff --git a/tsconfig.json b/tsconfig.json
index 7556e1d..fbc6fef 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -17,6 +17,9 @@
"allowJs": true,
"types": [
"bun-types" // add Bun global
- ]
+ ],
+ "paths": {
+ "@/*": ["./*"]
+ }
}
}
diff --git a/utils/index.ts b/utils/index.ts
new file mode 100644
index 0000000..b2e38c1
--- /dev/null
+++ b/utils/index.ts
@@ -0,0 +1,2 @@
+export * from "./jsonds";
+export * from "./point2d";
diff --git a/utils/jsonds.ts b/utils/jsonds.ts
new file mode 100644
index 0000000..c717232
--- /dev/null
+++ b/utils/jsonds.ts
@@ -0,0 +1,66 @@
+export class JSONSet<T extends Object> {
+ private items: Set<string>;
+
+ constructor() {
+ this.items = new Set<string>();
+ }
+
+ add(item: T): void {
+ const itemJson = JSON.stringify(item, Object.keys(item).sort());
+ this.items.add(itemJson);
+ }
+
+ has(item: T): boolean {
+ const itemJson = JSON.stringify(item, Object.keys(item).sort());
+ return this.items.has(itemJson);
+ }
+
+ delete(item: T): boolean {
+ const itemJson = JSON.stringify(item, Object.keys(item).sort());
+ return this.items.delete(itemJson);
+ }
+
+ clear(): void {
+ this.items.clear();
+ }
+
+ get size(): number {
+ return this.items.size;
+ }
+}
+
+export class JSONHashMap<T extends Object> {
+ private map: Map<string, T>;
+
+ constructor() {
+ this.map = new Map<string, T>();
+ }
+
+ set(key: T, value: T): void {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ this.map.set(keyJson, value);
+ }
+
+ get(key: T): T | undefined {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ return this.map.get(keyJson);
+ }
+
+ has(key: T): boolean {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ return this.map.has(keyJson);
+ }
+
+ delete(key: T): boolean {
+ const keyJson = JSON.stringify(key, Object.keys(key).sort());
+ return this.map.delete(keyJson);
+ }
+
+ clear(): void {
+ this.map.clear();
+ }
+
+ get size(): number {
+ return this.map.size;
+ }
+}
diff --git a/utils/point2d.ts b/utils/point2d.ts
new file mode 100644
index 0000000..3d07569
--- /dev/null
+++ b/utils/point2d.ts
@@ -0,0 +1,9 @@
+export type Vec2 = {
+ x: number;
+ y: number;
+};
+
+export const l2Norm = (p1: Vec2, p2: Vec2) =>
+ Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
+
+export const isDiagAdj = (p1: Vec2, p2: Vec2) => l2Norm(p1, p2) <= Math.sqrt(2);