This project has been created as part of the 42 curriculum by anrogard and kacherch.
A-Maze-ing is a procedural maze generator written in Python. Given a configuration file, it generates a random maze, writes it to an output file using a hexadecimal wall-encoding format, and displays it visually in the terminal. The maze can optionally be perfect β meaning there is exactly one path between the entry and the exit.
Key features:
- Reproducible generation via a seed
- Perfect maze mode (single path between entry and exit)
- A hidden "42" pattern embedded in the maze using fully-closed cells
- Interactive terminal display: toggle the solution path, change wall colors, regenerate
- A reusable
mazegenPython package that can be installed via pip
- Python 3.10 or later
- Poetry for dependency management
git clone https://github.com/ROGARD18/A-Maze-ing.git
cd A-Maze-ing
make installmake run
# equivalent to:
poetry run python3 a_maze_ing.py config.txtYou can pass a different config file:
poetry run python3 a_maze_ing.py my_config.txt| Target | Description |
|---|---|
make install |
Install dependencies via Poetry |
make run |
Run the program with the default config.txt |
make debug |
Run in debug mode (pdb) |
make clean |
Remove output file and caches |
make lint |
Run flake8 and mypy with standard flags |
make lint-strict |
Run flake8 and mypy with --strict |
The configuration file uses KEY=VALUE pairs, one per line. Lines starting with # are treated as comments and ignored.
| Key | Description | Example |
|---|---|---|
WIDTH |
Maze width in cells | WIDTH=20 |
HEIGHT |
Maze height in cells | HEIGHT=15 |
ENTRY |
Entry cell coordinates x,y |
ENTRY=0,0 |
EXIT |
Exit cell coordinates x,y |
EXIT=19,14 |
OUTPUT_FILE |
Path to the output file | OUTPUT_FILE=maze.txt |
PERFECT |
Whether to generate a perfect maze | PERFECT=True |
| Key | Description | Example |
|---|---|---|
SEED |
Integer or float seed for reproducibility | SEED=42 |
WIDTH=9
HEIGHT=9
ENTRY=0,0
EXIT=8,8
OUTPUT_FILE=maze.txt
PERFECT=True
SEED=2
Each cell is encoded as a single hexadecimal digit representing which walls are closed. Each bit corresponds to a direction:
| Bit | Direction |
|---|---|
| 0 (LSB) | North |
| 1 | East |
| 2 | South |
| 3 | West |
A closed wall sets the bit to 1, an open passage sets it to 0.
Example: A (binary 1010) means the East and West walls are closed.
Cells are written row by row, one row per line. After an empty line, three additional lines follow:
- Entry coordinates (
x,y) - Exit coordinates (
x,y) - Shortest path from entry to exit using
N,E,S,W
This project uses the recursive backtracker algorithm (also known as depth-first search with backtracking).
How it works:
- Start at a random cell, mark it as visited.
- Randomly choose an unvisited neighbor, remove the wall between them, and recurse.
- If no unvisited neighbors remain, backtrack to the previous cell.
- Repeat until all cells have been visited.
Why this algorithm?
The recursive backtracker produces mazes with long, winding corridors and relatively few dead ends, which makes it visually interesting and gives a satisfying feel to the "42" pattern. It natively produces a perfect maze (a spanning tree of the grid), satisfying the PERFECT=True constraint without additional post-processing. It is also simple to implement, easy to reason about, and efficient enough for the maze sizes required by this project.
The program offers an interactive terminal display with the following controls:
- Re-generate a new maze with a fresh random seed
- Show/Hide the shortest path from entry to exit
- Rotate wall colors through a preset palette
- Quit
The display clearly marks the entry (colored cell), the exit (colored cell), walls, open passages, and β when toggled β the solution path highlighted in a distinct color.
The maze always includes a visible "42" pattern composed of fully-closed cells. If the maze is too small to fit the pattern, a message is printed to the console.
The maze generation logic is packaged as a standalone Python package called mazegen, located in the mazegen/ directory.
From the root of the repository, in a virtual environment:
pip install build
python -m build
pip install dist/mazegen-1.0.0-py3-none-any.whlOr install directly from source:
pip install .from mazegen import MazeGenerator
# Instantiate with custom parameters
gen = MazeGenerator(width=20, height=15, seed=42, perfect=True)
# Generate the maze
gen.generate()
# Access the maze grid
grid = gen.maze # 2D list of cells, each cell is an int (hex wall bitmask)
# Access the solution (list of directions: 'N', 'E', 'S', 'W')
path = gen.solve(entry=(0, 0), exit=(19, 14))
print("Shortest path:", path)| Parameter | Type | Description |
|---|---|---|
width |
int |
Number of columns |
height |
int |
Number of rows |
seed |
int | float | None |
Random seed for reproducibility |
perfect |
bool |
If True, generates a perfect maze |
gen.mazeβ 2D list of integers (one per cell), where each integer encodes walls as a 4-bit bitmask (N=bit0, E=bit1, S=bit2, W=bit3).gen.solve(entry, exit)β Returns the shortest path as a list of direction characters.
Note: the internal maze structure uses a bitmask per cell, which is the same format as the output file.
| Member | Role |
|---|---|
| anrogard | Sole developer β architecture, generation algorithm, visual display |
| kacherch | Sole developer β architecture, generation algorithm, packaging |
The project was initially scoped as a two-week sprint:
In practice, the constraint-satisfaction logic for the "42" pattern and the open-area restriction (no 3Γ3 open zones) required more iteration than anticipated, shifting the timeline slightly. The packaging step was completed last and proved straightforward with setuptools and pyproject.toml.
- The recursive backtracker was a natural fit for the perfect maze requirement and produced clean, explorable mazes immediately.
- Using
pydanticfor config validation caught bad inputs early with clear error messages. - Separating the generation logic into a standalone
mazegenpackage from the start made the final packaging step trivial.
- Adding support for multiple generation algorithms (Prim's, Kruskal's) as a bonus.
- A graphical display using MiniLibX instead of β or in addition to β the terminal renderer.
- More comprehensive unit tests for edge cases (1Γ1 maze, entry == exit border cases).
- Poetry β dependency management and virtual environments
- pydantic β config validation with type safety
- flake8 + mypy β linting and static type checking
- Claude (Anthropic) β used for generating documentation drafts and README structure, then reviewed and adapted manually
- Maze generation algorithms β Wikipedia
- Recursive backtracker explained β think-maths.co.uk
- Spanning trees and perfect mazes β astrolog.org
- Python type hints β PEP 484
- PEP 257 β Docstring conventions
- pydantic documentation
AI was used to assist with:
- Drafting and structuring this README