## ~shreyasminocha/maze-solver

ee50a7de6767e17b4241e3a3db9fb5e9115c2bde — Shreyas Minocha 9 months ago
```Initialize repository
```
```2 files changed, 98 insertions(+), 0 deletions(-)

A maze.py
```
`A  => README.md +1 -0`
```@@ 1,1 @@
+Need a shitty maze solver for a CTF? Well here you go.

```
`A  => maze.py +97 -0`
```@@ 1,97 @@
+from collections import defaultdict
+from enum import Enum
+from typing import Dict, List, Set, Tuple
+
+
+class Direction(Enum):
+    Up = "n"
+    Down = "s"
+    Left = "w"
+    Right = "e"
+
+
+Maze = List[str]
+CellCoords = Tuple[int, int]
+Graph = Dict[CellCoords, Set[CellCoords]]
+
+
+def solve_maze(
+    maze: Maze, start_indicator: str, goal_indicator: str, wall_indicator: str
+) -> List[Direction]:
+    assert len(set(map(len, maze))) == 1
+    assert len(start_indicator) == len(goal_indicator) == len(wall_indicator) == 1
+
+    start, goal = None, None
+    for r, row in enumerate(maze):
+        for c, cell in enumerate(row):
+            if cell == start_indicator:
+                start = (r, c)
+            if cell == goal_indicator:
+                goal = (r, c)
+
+    if start is None:
+    if goal is None:
+
+    def graphify(grid: Maze) -> Graph:
+        m, n = len(grid), len(grid[0])
+
+        graph = defaultdict(set)
+        for r, row in enumerate(grid):
+            for c, cell in enumerate(row):
+                for dr, dc in [(0, -1), (0, 1), (1, 0), (-1, 0)]:
+                    if 0 <= r + dr < m and 0 <= c + dc < n:
+                        if cell != wall_indicator:
+                            if grid[r + dr][c + dc] != wall_indicator:
+                                graph[(r, c)].add((r + dr, c + dc))
+                                graph[(r + dr, c + dc)].add((r, c))
+
+        return graph
+
+    def bfs(graph: Graph, node: CellCoords) -> Dict[CellCoords, CellCoords]:
+        queue = [node]
+        distance: Dict[CellCoords, float] = defaultdict(lambda: float("inf"))
+
+        distance[node] = 0
+        visited = {node: True}
+        ancestors = {node: node}
+
+        while queue:
+            curr = queue.pop()
+            visited[curr] = True
+            for nbr in graph[curr]:
+                distance[nbr] = min(distance[nbr], distance[curr] + 1)
+                if nbr not in visited:
+                    ancestors[nbr] = curr
+                    queue.append(nbr)
+
+        return ancestors
+
+    def traceback(
+        anc: Dict[CellCoords, CellCoords], start: CellCoords, goal: CellCoords
+    ) -> List[Direction]:
+        curr = goal
+        directions = []
+        while curr != start:
+            new = anc[curr]
+            if curr[0] > new[0]:
+                directions.append(Direction.Down)
+            elif curr[1] > new[1]:
+                directions.append(Direction.Right)
+            elif curr[1] < new[1]:
+                directions.append(Direction.Left)
+            elif curr[0] < new[0]:
+                directions.append(Direction.Up)
+            else:
+                raise ValueError("unreachable destination?")
+
+            curr = new
+        return directions[::-1]
+
+    graph = graphify(maze)
+
+    ancestors = bfs(graph, start)
+    dirs = traceback(ancestors, start, goal)
+
+    return dirs

```