How to Create a Maze Generator in Pure Batch Script
Generating a mathematically perfect maze entirely within a Windows Command Prompt window is one of the most impressive demonstrations of what Batch scripting can achieve. Because Batch lacks native recursion, multidimensional arrays, and complex data structures, building a maze requires careful algorithmic translation. The most reliable approach for this is the Recursive Backtracker (a Depth-First Search variant), which guarantees a "perfect" maze: every cell is reachable, there are no isolated areas, and zero loops exist.
The Strategy: Recursive Backtracker
A perfect maze is essentially a spanning tree carved into a grid of walls. The algorithm works by exploring as far as possible down a random path, then backtracking when it hits a dead end. Here's how we map that concept to Batch:
- The Grid Layout: We use a coordinate system where odd indices represent cells (potential paths) and even indices represent walls. This spacing naturally prevents diagonal movement and simplifies wall removal.
- Initialization: Every coordinate is set to a wall character (
#). AstartX,startYcell is marked as a path and flagged as visited. - Simulated Recursion: Since Batch cannot call itself recursively, we simulate a call stack using a
toppointer and indexed environment variables (stackX_!top!,stackY_!top!). - The Carving Loop:
- Check all four cardinal neighbors (N, S, E, W) for unvisited cells.
- If valid neighbors exist, randomly select one.
- Knock down the wall between the current cell and the chosen neighbor.
- Mark the new cell as visited, push the old coordinates onto the stack, and move forward.
- If no neighbors remain, pop the stack and backtrack.
The Complete Script
This implementation uses an index-based stack rather than string parsing. While string manipulation can simulate a stack in Batch, indexed variables are significantly faster and more reliable inside tight generation loops.
@echo off
setlocal EnableExtensions EnableDelayedExpansion
:: Console setup
mode con: cols=45 lines=25
title Batch Maze Generator
color 0A
:: Maze size (odd numbers)
set "width=39"
set "height=19"
:: Ensure odd (just in case)
set /a "width|=1, height|=1"
set /a "wMax=width-1, hMax=height-1"
echo Generating Maze...
:: 1) Fill grid with walls
for /l %%Y in (1,1,%height%) do (
for /l %%X in (1,1,%width%) do (
set "cell_%%X_%%Y=#"
)
)
:: 2) Perfect maze generation (recursive backtracker using a stack)
set "startX=2"
set "startY=2"
set "cell_%startX%_%startY%= "
set "vis_%startX%_%startY%=1"
set /a top=0
set "stackX_0=%startX%"
set "stackY_0=%startY%"
:MazeLoop
if !top! lss 0 goto MazeDone
for %%T in (!top!) do (
set "cx=!stackX_%%T!"
set "cy=!stackY_%%T!"
)
set /a c=0
for %%D in (0 1 2 3) do (
set "nx=!cx!"
set "ny=!cy!"
if %%D==0 set /a ny-=2
if %%D==1 set /a nx+=2
if %%D==2 set /a ny+=2
if %%D==3 set /a nx-=2
if !nx! geq 2 if !nx! leq !wMax! if !ny! geq 2 if !ny! leq !hMax! (
if not defined vis_!nx!_!ny! (
set /a c+=1
set "candDir_!c!=%%D"
)
)
)
if !c! equ 0 (
set /a top-=1
goto MazeLoop
)
set /a pick=!RANDOM! %% c + 1
for %%I in (!pick!) do set "dir=!candDir_%%I!"
set "nx=!cx!"
set "ny=!cy!"
if !dir! equ 0 set /a ny-=2
if !dir! equ 1 set /a nx+=2
if !dir! equ 2 set /a ny+=2
if !dir! equ 3 set /a nx-=2
set /a "wx=(cx+nx)/2, wy=(cy+ny)/2"
set "cell_!wx!_!wy!= "
set "cell_!nx!_!ny!= "
set "vis_!nx!_!ny!=1"
set /a top+=1
set "stackX_!top!=!nx!"
set "stackY_!top!=!ny!"
goto MazeLoop
:MazeDone
:: 3) Entrance and exit
set "cell_2_1= "
set /a "exitX=width-1, exitY=height-1"
set "cell_!exitX!_!exitY!= "
set "cell_!exitX!_!height!= "
:: 4) Render
cls
echo =======================================
echo LABYRINTH GENERATOR
echo =======================================
for /l %%Y in (1,1,%height%) do (
set "rowStr="
for /l %%X in (1,1,%width%) do (
set "rowStr=!rowStr!!cell_%%X_%%Y!"
)
echo !rowStr!
)
echo =======================================
pause
exit /b
How the Engine Works Under the Hood
1. Flat Environment Variables as a 2D Grid
Batch doesn't support true arrays. Instead, the script uses dynamically named variables like cell_5_7 or vis_12_15. This flat mapping is surprisingly efficient and allows direct coordinate access without complex parsing.
2. The Index-Based Stack
Rather than relying on slow string concatenation/splitting to simulate push/pop operations, the script maintains a top counter. Coordinates are pushed by incrementing top and storing values in stackX_!top! and stackY_!top!. Backtracking is as simple as set /a top-=1. This approach mimics CPU register stacking and runs noticeably faster in tight loops.
3. Neighbor Validation & Random Selection
The for %%D in (0 1 2 3) loop checks North, East, South, and West. Valid, unvisited neighbors are stored in temporary candDir_!c! variables. The script then uses !RANDOM! %% c + 1 to pick a random direction from the available candidates, ensuring the maze remains unpredictable while staying mathematically perfect.
4. Wall Removal & Rendering
When a neighbor is chosen, the script calculates the midpoint coordinates (wx, wy) between the current cell and the target. Setting that midpoint to a space character effectively "knocks down" the wall. After generation completes, a double-nested loop reconstructs each row into a single string and prints it, producing the final ASCII maze.
Why This Approach Excels in Batch
The Recursive Backtracker translates exceptionally well to Batch's limitations. By separating path cells (odd coordinates) from walls (even coordinates), the algorithm avoids complex collision checks. The index-based stack eliminates the overhead of string tokenization, and delayed expansion (!var!) ensures real-time variable resolution inside loops.
Conclusion
Creating a perfect maze generator natively in Command Prompt forces a deep understanding of algorithmic translation. Converting mathematical vectors into flat environment variables, simulating memory stacks with simple counters, and orchestrating hundreds of sequential logic gates proves that Batch is far more capable than its reputation suggests. With this engine as a foundation, you can easily extend it with player input, pathfinding solvers, or dynamic resizing to build a complete terminal-based game.