Welcome, guest | Sign In | My Account | Store | Cart

Random maze generator using depth-first search.

It starts the maze path from a random cell and there is no exit defined but actually any 2 cells on the path (white cells) can be assigned to be entry and exit locations. (I could just add code to randomly select 2 white cells and change their colors to something else but I thought it looks better this way.)

Python, 43 lines
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 # Random Maze Generator using Depth-first Search # http://en.wikipedia.org/wiki/Maze_generation_algorithm # FB - 20121214 import random from PIL import Image imgx = 500; imgy = 500 image = Image.new("RGB", (imgx, imgy)) pixels = image.load() mx = 50; my = 50 # width and height of the maze maze = [[0 for x in range(mx)] for y in range(my)] dx = [0, 1, 0, -1]; dy = [-1, 0, 1, 0] # 4 directions to move in the maze color = [(0,0, 0), (255, 255, 255)] # RGB colors of the maze # start the maze from a random cell stack = [(random.randint(0, mx - 1), random.randint(0, my - 1))] while len(stack) > 0: (cx, cy) = stack[-1] maze[cy][cx] = 1 # find a new cell to add nlst = [] # list of available neighbors for i in range(4): nx = cx + dx[i]; ny = cy + dy[i] if nx >= 0 and nx < mx and ny >= 0 and ny < my: if maze[ny][nx] == 0: # of occupied neighbors must be 1 ctr = 0 for j in range(4): ex = nx + dx[j]; ey = ny + dy[j] if ex >= 0 and ex < mx and ey >= 0 and ey < my: if maze[ey][ex] == 1: ctr += 1 if ctr == 1: nlst.append(i) # if 1 or more neighbors available then randomly select one and move if len(nlst) > 0: ir = nlst[random.randint(0, len(nlst) - 1)] cx += dx[ir]; cy += dy[ir] stack.append((cx, cy)) else: stack.pop() # paint the maze for ky in range(imgy): for kx in range(imgx): pixels[kx, ky] = color[maze[my * ky / imgy][mx * kx / imgx]] image.save("Maze_" + str(mx) + "x" + str(my) + ".png", "PNG") Matt Jones 9 years, 1 month ago

This would have been easier to read if you used more meaningful variable names. Looks good otherwise. FB36 (author) 9 years, 1 month ago

This is the recursive version (so it uses a stack implicitly instead of explicitly):

# Random Maze Generator using Depth-first Search (Recursive Version)
# http://en.wikipedia.org/wiki/Maze_generation_algorithm
# FB - 20121205
import random
from PIL import Image
imgx = 512; imgy = 512
image = Image.new("RGB", (imgx, imgy))
mx = 40; my = 40 # width and height of the maze
maze = [[0 for x in range(mx)] for y in range(my)]
dx = [0, 1, 0, -1]; dy = [-1, 0, 1, 0] # directions to move in the maze

def GenerateMaze(cx, cy):
maze[cy][cx] = 1
while True:
# find a new cell to add
nlst = [] # list of available neighbors
for i in range(4):
nx = cx + dx[i]; ny = cy + dy[i]
if nx >= 0 and nx < mx and ny >= 0 and ny < my:
if maze[ny][nx] == 0:
# of occupied neighbors of the candidate cell must be 1
ctr = 0
for j in range(4):
ex = nx + dx[j]; ey = ny + dy[j]
if ex >= 0 and ex < mx and ey >= 0 and ey < my:
if maze[ey][ex] == 1: ctr += 1
if ctr == 1: nlst.append(i)
# if 1 or more available neighbors then randomly select one and add
if len(nlst) > 0:
ir = nlst[random.randint(0, len(nlst) - 1)]
cx += dx[ir]; cy += dy[ir]
GenerateMaze(cx, cy)
else: break

GenerateMaze(0, 0)
# paint the maze
for ky in range(imgy):
for kx in range(imgx):
m = maze[my * ky / imgy][mx * kx / imgx] * 255
pixels[kx, ky] = (m, m, m)
image.save("RandomMaze_" + str(mx) + "x" + str(my) + ".png", "PNG") FB36 (author) 9 years ago

This version does not allow zigzag corridors, so the maze looks more conventional:

# Random Maze Generator using Depth-first Search
# http://en.wikipedia.org/wiki/Maze_generation_algorithm
# FB36 - 20130106
import random
from PIL import Image
imgx = 500; imgy = 500
image = Image.new("RGB", (imgx, imgy))
mx = 100; my = 100 # width and height of the maze
maze = [[0 for x in range(mx)] for y in range(my)]
dx = [0, 1, 0, -1]; dy = [-1, 0, 1, 0] # 4 directions to move in the maze
color = [(0, 0, 0), (255, 255, 255)] # RGB colors of the maze
# start the maze from a random cell
cx = random.randint(0, mx - 1); cy = random.randint(0, my - 1)
maze[cy][cx] = 1; stack = [(cx, cy, 0)] # stack element: (x, y, direction)

while len(stack) > 0:
(cx, cy, cd) = stack[-1]
# to prevent zigzags:
# if changed direction in the last move then cannot change again
if len(stack) > 2:
if cd != stack[-2]: dirRange = [cd]
else: dirRange = range(4)
else: dirRange = range(4)

# find a new cell to add
nlst = [] # list of available neighbors
for i in dirRange:
nx = cx + dx[i]; ny = cy + dy[i]
if nx >= 0 and nx < mx and ny >= 0 and ny < my:
if maze[ny][nx] == 0:
ctr = 0 # of occupied neighbors must be 1
for j in range(4):
ex = nx + dx[j]; ey = ny + dy[j]
if ex >= 0 and ex < mx and ey >= 0 and ey < my:
if maze[ey][ex] == 1: ctr += 1
if ctr == 1: nlst.append(i)

# if 1 or more neighbors available then randomly select one and move
if len(nlst) > 0:
ir = nlst[random.randint(0, len(nlst) - 1)]
cx += dx[ir]; cy += dy[ir]; maze[cy][cx] = 1
stack.append((cx, cy, ir))
else: stack.pop()

# paint the maze
for ky in range(imgy):
for kx in range(imgx):
pixels[kx, ky] = color[maze[my * ky / imgy][mx * kx / imgx]]
image.save("Maze_" + str(mx) + "x" + str(my) + ".png", "PNG") Muhammad Khalifa 7 years, 5 months ago

Why do you have to check every neighbor if it has only one visited neighbor? Can't we just choose a random neighbor x,y where maze[y][x]=0 , set maze[y][x] to 1 and add it the stack? Created by FB36 on Wed, 5 Dec 2012 (MIT)