class Queue { private items: T[]; constructor() { this.items = []; } enqueue(item: T): void { this.items.push(item); } dequeue(): T | undefined { return this.items.shift(); } isEmpty(): boolean { return this.items.length === 0; } } type index = { x: number; y: number; } export class BFSPathfinding { private map: number[][]; private visited: boolean[][]; private rows: number; private cols: number; private directions: index[]; constructor() { this.map = []; this.rows = 0; this.cols = 0; this.visited = []; this.directions = []; } setMap(map: number[][]) { this.map = map; this.rows = this.map.length; this.cols = this.map[0].length; this.visited = Array.from({ length: this.rows }, () => Array(this.cols).fill(false)); this.directions = [{ x: 0, y: -1 }, { x: 0, y: 1 }, { x: -1, y: 0 }, { x: 1, y: 0 }]; } findPath(start: index, end: index): index[] { if (this.map[start.y][start.x] !== 0 || this.map[end.y][end.x] !== 0) { return []; } const queue = new Queue(); const prev: index[][] = Array.from({ length: this.rows }, () => Array(this.cols).fill(null)); queue.enqueue(start); this.visited[start.y][start.x] = true; while (!queue.isEmpty()) { const current = queue.dequeue()!; if (current.x === end.x && current.y === end.y) { return this.constructPath(prev, start, end); } for (const direction of this.directions) { const nextX = current.x + direction.x; const nextY = current.y + direction.y; if (this.isValid(nextX, nextY) && this.map[nextY][nextX] === 0 && !this.visited[nextY][nextX]) { queue.enqueue({ x: nextX, y: nextY }); this.visited[nextY][nextX] = true; prev[nextY][nextX] = current; } } } return []; } private isValid(x: number, y: number): boolean { return x >= 0 && x < this.cols && y >= 0 && y < this.rows; } private constructPath(prev: index[][], start: index, end: index): index[] { const path: index[] = []; let current = end; while (current !== start) { path.unshift(current); current = prev[current.y][current.x]!; } path.unshift(start); return path; } }