Alice just saw a talking white rabbit wearing a waistcoat, running past her shouting "Oh dear! Oh dear! I shall be too late!". Weird.
She needs to follow the rabbit through a maze-like place. Our goal in this project is to solve mazes in a reasonable amount of time and show the solution.
-
Two pathfinding algorithms:
- BFS (Breadth-First Search) - Guarantees shortest path
- A-star - Heuristic-based, more efficient exploration
-
Performance measurement:
- Execution time (milliseconds)
- Cells visited during search
- Solution path length
-
Flexible maze support:
- Maze sizes: 1x1 to 10000x10000
- ASCII format (
*= free space,X= wall,o= solution path) - 4-directional movement (up, down, left, right)
-
Smart validation:
- Detects blocked start/finish positions
- Handles invalid maze formats
- Reports "no solution found" when appropriate
| Category | Command | Description |
|---|---|---|
| Build | make |
Compile the project |
make re |
Clean and recompile | |
make clean |
Remove object files | |
make fclean |
Remove all generated files | |
| Main Test | make test |
Comprehensive test suite: All mazes with both BFS & A* + stats. Saves results to tests/results/ |
| Algorithm Tests | make test-bfs |
Run all tests with BFS only |
make test-astar |
Run all tests with A* only | |
make test-stats |
All tests with BFS + stats | |
make test-astar-stats |
All tests with A* + stats | |
make test-compare |
Compare BFS vs A* side-by-side | |
| Single File | make test-single FILE=<path> |
Test specific maze |
make test-single-stats FILE=<path> |
Test specific maze with both algorithms + stats |
Every test execution will display:
- The solved maze - Path marked with
ofrom start (0,0) to finish - Status message:
- SOLVED :) - When a solution path is found
- UNSOLVED :( - When no solution exists
- Performance statistics:
- Algorithm used (BFS or A*)
- Execution time in milliseconds
- Number of cells visited
- Solution path length
- Rectangular mazes coded in ASCII
*represents free spaces (passable)Xrepresents walls (impassable)- Start: Upper-left corner
(0, 0) - Finish: Bottom-right corner
(width-1, height-1) - Solution: Marked with
ocharacters from start to finish - Last line doesn't terminate with a newline
Input (24x6):
*****XX****X********XXXX
XX******XX***XXXXX***XXX
XX***XXXX**XXXXX****XXXX
XX***XXXXXXXXXXXXXX****X
*****XXXXXX****XX***XXXX
XX*************XXXX*****
Solved:
oooooXXooooXooooooooXXXX
XX**ooooXXoooXXXXX*o*XXX
XX***XXXX**XXXXX***oXXXX
XX***XXXXXXXXXXXXXXo***X
*****XXXXXX****XX**oXXXX
XX*************XXXXooooo
- Time complexity: O(W × H)
- Space complexity: O(W × H)
- Guarantees: Shortest path
- Best for: Small to medium mazes, when shortest path is critical
- Time complexity: O(W × H) worst case, often much better
- Space complexity: O(W × H)
- Heuristic: Manhattan distance
- Best for: Large mazes, when efficiency matters
solver/
├── include/
│ ├── queue.h # Queue data structure (for BFS)
│ ├── priority_queue.h # Min-heap (for A*)
│ └── solver.h # Main header with structs and functions
├── src/
│ ├── main.c # Entry point, CLI parsing
│ ├── maze.c # Maze loading and I/O
│ ├── validation.c # Maze validation
│ ├── queue.c # Queue implementation
│ ├── priority_queue.c # Priority queue implementation
│ ├── solver_bfs.c # BFS algorithm
│ └── solver_astar.c # A* algorithm
├── tests/
│ └── generated/ # Test cases (1x1 to 5000x5000)
| └── results/ # Tests results
├── Makefile # Build system and run tests and algorithms
└── README.md # This file
Implemented with queue structures, BFS explores the maze level by level, ensuring the shortest path is found:
- Start from (0,0)
- Explore all neighbors at distance 1
- Then all neighbors at distance 2
- Continue until reaching the goal or exploring all reachable cells
Pros:
- Guarantees shortest path
- Simple to implement
Cons:
- Explores many unnecessary cells
- Memory-intensive for large mazes
A* uses a heuristic function (Manhattan distance) to prioritize which cells to explore:
- Maintain
g(n)= actual cost from start to current cell - Calculate
h(n)= heuristic (Manhattan distance to goal) - Priority =
f(n) = g(n) + h(n) - Always explore the cell with lowest
f(n)
Manhattan Distance Heuristic:
h(x, y) = |x - goal_x| + |y - goal_y|
Pros:
- More efficient exploration
- Fewer cells visited
- Still guarantees shortest path (with admissible heuristic)
Cons:
- Slightly more complex implementation
- Requires priority queue
The project includes comprehensive test mazes and multiple testing modes.
All test files are located in tests/generated/:
| File | Size | Description |
|---|---|---|
test_5x5_simple.txt |
5×5 | Simple maze |
test_24x6.txt |
24×6 | Wide maze |
test_20x20.txt |
20×20 | Medium complexity |
test_complex_20x20.txt |
20×20 | High complexity pattern |
test_medium.txt |
20×20 | Nested paths |
test_large.txt |
28×19 | Large complex maze |
test_no_solution.txt |
3×3 | Unsolvable maze |
# Comprehensive test (RECOMMENDED)
make test # All mazes with BOTH algorithms + stats
# Saves results to tests/results/test_results_YYYYMMDD_HHMMSS.txt
# Individual algorithm tests
make test-bfs # All tests with BFS only
make test-astar # All tests with A* only
make test-stats # All tests with BFS + stats
make test-astar-stats # All tests with A* + stats
make test-compare # Side-by-side BFS vs A* comparison
# Single file testing
make test-single FILE=tests/generated/test_5x5_simple.txt
make test-single-stats FILE=tests/generated/test_24x6.txt