From 03efb6e64cb3f473a54ee5558952ea4cd826e58e Mon Sep 17 00:00:00 2001 From: Eric Xu Date: Wed, 10 Jul 2024 04:05:10 -0400 Subject: [PATCH] Add BFS solving algorithm --- package-lock.json | 7 +++++ package.json | 1 + src/lib/algorithms/solving/BFS.ts | 41 +++++++++++++++++++++++++ src/lib/algorithms/solving/pathUtils.ts | 14 +++++++++ 4 files changed, 63 insertions(+) create mode 100644 src/lib/algorithms/solving/BFS.ts create mode 100644 src/lib/algorithms/solving/pathUtils.ts diff --git a/package-lock.json b/package-lock.json index 240a3d6..1f9cf43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "mazejs", "version": "0.1.0", "dependencies": { + "@datastructures-js/deque": "^1.0.4", "async-mutex": "^0.5.0", "immer": "^10.1.1", "next": "14.2.4", @@ -532,6 +533,12 @@ "node": ">=6.9.0" } }, + "node_modules/@datastructures-js/deque": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@datastructures-js/deque/-/deque-1.0.4.tgz", + "integrity": "sha512-zlgVSsxqiAd+scLUILvx8E887o+6kYds9/d4DCM/mFOuUITUlPG/r3u5iPZjzW3o6XPPi+p66p3Kf1+wFxYvLQ==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", diff --git a/package.json b/package.json index 285f503..b9682fc 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "test": "vitest" }, "dependencies": { + "@datastructures-js/deque": "^1.0.4", "async-mutex": "^0.5.0", "immer": "^10.1.1", "next": "14.2.4", diff --git a/src/lib/algorithms/solving/BFS.ts b/src/lib/algorithms/solving/BFS.ts new file mode 100644 index 0000000..b00d4ba --- /dev/null +++ b/src/lib/algorithms/solving/BFS.ts @@ -0,0 +1,41 @@ +import { MazeCell } from "@/lib/MazeCell"; +import { MazeSolver } from "./MazeSolver"; +import { Deque } from "@datastructures-js/deque"; +import { buildPath } from "./pathUtils"; + +export class BFS extends MazeSolver { + private queue = new Deque(); + private cameFrom = new Map(); + + protected _step(): [boolean, Readonly[]] { + const changes: MazeCell[] = []; + + // Go through one queue level + const queueSize = this.queue.size(); + for (let i = 0; i < queueSize; ++i) { + const current = this.queue.popFront(); + + if (current === this.end) { + this._path = buildPath(this.cameFrom, this.end); + return [true, []]; + } + + for (const neighbor of current.connections) { + if (neighbor.state === "solid") { + neighbor.state = "partial"; + this.queue.pushBack(neighbor); + this.cameFrom.set(neighbor, current); + changes.push(neighbor); + } + } + } + + return [this.queue.isEmpty(), changes]; + } + + protected initialize(): Readonly[] { + this.start.state = "partial"; + this.queue.pushBack(this.start); + return [this.start]; + } +} diff --git a/src/lib/algorithms/solving/pathUtils.ts b/src/lib/algorithms/solving/pathUtils.ts new file mode 100644 index 0000000..e69b671 --- /dev/null +++ b/src/lib/algorithms/solving/pathUtils.ts @@ -0,0 +1,14 @@ +import { MazeCell } from "@/lib/MazeCell"; + +export function buildPath( + cameFrom: Map, + end: MazeCell, +): MazeCell[] { + const path: MazeCell[] = []; + let current: MazeCell | null = end; + while (current !== null) { + path.unshift(current); + current = cameFrom.get(current) ?? null; + } + return path.toReversed(); +}