Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maze Algorithms

Purpose

An algorithmic maze generator and pathfinder with Pygame visualization. The generation algorithm builds a maze as a 2D NumPy array with values indicating walls, paths, and entry/exit; then, another algorithm solves the generated maze; finally, a Pygame visualizer displays generation and pathfinding, and statistic results are shown in-terminal.

This project was selected as an introduction to algorithmic simulations. As a learning project, the project introduced me to Pygame and heapq while expanding my existing complex-data skillset (NumPy, especially). Originally, the project was based exclusively around pathfinding; however, the generation aspect quickly became an equal focus.

Architecture

  • generation/ — Contains multiple generation algorithms to build and pass a completed maze. Results are returned as a normalized GenerationResult dataclass.
  • pathfinding/ — Variety of pathfinding algorithms that solve a completed maze using a unique strategy. Results are returned as a normalized PathfindingResult dataclass.
  • outputs/ — Result handling, including statistic calculations and generation/pathfinding visualization.
    • visualizer.py — GenerationVisualizer + PathfindingVisualizer, both Pygame-based. Carve order and exploration order are animated in sequence, with a "search head" highlight showing the active frontier cell.
    • stats.py — Terminal-printed mean/median/stdev/min/max per stat over full run
  • main.py — SingleRun / MultiRun orchestration, episode-count-driven routing
  • cli.py — Command argparse for maze dimensions and cell-size

Algorithms

Additional generation and pathfinding algorithms will be added over time. Currently, two generation algorithms and two pathfinding algorithms are fully implemented.

Generation

  • recursive_backtracking.py — Iterative stack-based carving using DFS-similar approach; avoided fixed Python recursion-depth limits by moving the call stack into an explicit, heap-allocated list.
  • prims.py — Heap-based frontier carving with lazy deletion; frontier cells pushed with a random priority and only validated against the maze on pop, avoiding the O(n) cost (list-removal and membership checking) of live, deduplicated frontier.

Pathfinding

  • bfs.py — Queue-based algorithm (dependent on path-copying deque system) that explores breadth-first; duplicate queueing combated via at-discovery "visited" tagging (rather than at-processing)
  • dfs.py — Stack-based algorithm (dependent on path-copying list system) that explores depth-first along a single path; like BFS, combats duplicate data via at-discovery tagging.

Design Decisions

  • Initially, the system depended on a dictionary of (x, y) tuples for storing the maze itself. While time complexity was optimized (O(1)), the look-up demand at scale was too large: tuple hashing and per-entry Python object overhead for the key, value, and hash table slot. To combat this, a NumPy-based 2D array of [x][y] cells was implemented, simplifying to a single contiguous, fixed-type memory block. This system directly improved the memory footprint and real-time lookup speed.
  • The registry-based design, with generation/ and pathfinding/ folders, enables simplified addition of new algorithms. The modularity of the design means that any new algorithm is one self-contained file addition.
  • AlgorithmResult dataclasses were chosen as an extension to the simplified registry design, adding normalization across algorithms for efficient data processing.
  • Entry/Exit are fixed at (1, 1) and (width - 2, height - 2) as a strategy of deliberate simplicity. While passing an entry and exit upon generation is plausible, the guaranteed entry/exit coordinates allow for cross-run comparison between multiple algorithms without the possibility of entry/exit-skewed results.

Limitations

  • Maze dimensions must be odd-value (automatically enforced). Since any cell can be a wall or path (rather than path cells containing border-wall data), the carve algorithms check across a neighboring cell to determine if the cell can be carved. This preserves the outer border of the maze and ensures that paths remain 1-wide.
  • No weighted-cell support. Currently, algorithms that manage weighted cells, such as Dijkstra's, are unintegrated. The existing maze storage architecture marks 0/1 values as paths and walls—the complexity of cell weighting, especially given the wide variety of non-weighted algorithms available, seemed an unnecessary feature.
  • Perfect mazes only. Currently, no loops occur within generated mazes. Future generators, such as a loop-allowed iteration of Prim's algorithm, could use randomization to (rarely) allow loops to form rather than guaranteeing clean path-branch structures.
  • Stats are terminal only. Initially, full chart-based comparison architecture was designed. However, the system appeared entirely unnecessary—only a handful of stats, such as efficiency, actually offered comparative value. As such, I elected to remove the matplotlib-based chart architecture and return to a fully terminal-based system. Comparison can be achieved by manually saving statistic results and comparing pertinent datapoints, such as efficiency or generation time, across runs.

Setup

uv venv
uv sync

Usage

Command Syntax

uv run python main.py --width int --height int --cell-size int

Example Command

uv run python main.py --width 25 --height 25 --cell-size 5

Command Arguments

--width and --height default to 55 and dictate the dimensions of the generated maze. These dimensions remain the same for all generated mazes across a multiepisodic run. --cell-size defaults to 10 and dictates the pixel size per maze cell, used in Pygame visualization.

Repository Structure

generation/                 # Storage folder for generation algorithms
    recursive_backtracking.py
    prims.py
    result.py                   # GenerationResult dataclass
pathfinding/                # Storage folder for pathfinding algorithms
    bfs.py
    dfs.py
    result.py                   # PathfindingResult dataclass
outputs/                    # Folder for output systems, including Pygame visualization and statistics display
    visualizer.py
    stats.py
    result.py                   # RunResult dataclass (AlgorithmResult dataclasses + run-specific configs)
cli.py                      # argparse for cross-file dimension and pixel configurations
main.py                     # Main orchestration architecture

Releases

Packages

Contributors

Languages