In [2]:
# from http://en.wikipedia.org/wiki/Maze_generation_algorithm
import numpy
from numpy.random import random_integers as rand
import matplotlib.pyplot as pyplot
 
def maze(width=81, height=51, complexity=.75, density=.75):
    # Only odd shapes
    shape = ((height // 2) * 2 + 1, (width // 2) * 2 + 1)
    # Adjust complexity and density relative to maze size
    complexity = int(complexity * (5 * (shape[0] + shape[1])))
    density    = int(density * (shape[0] // 2 * shape[1] // 2))
    # Build actual maze
    Z = numpy.zeros(shape, dtype=bool)
    # Fill borders
    Z[0, :] = Z[-1, :] = 1
    Z[:, 0] = Z[:, -1] = 1
    # Make aisles
    for i in range(density):
        x, y = rand(0, shape[1] // 2) * 2, rand(0, shape[0] // 2) * 2
        Z[y, x] = 1
        for j in range(complexity):
            neighbours = []
            if x > 1:             neighbours.append((y, x - 2))
            if x < shape[1] - 2:  neighbours.append((y, x + 2))
            if y > 1:             neighbours.append((y - 2, x))
            if y < shape[0] - 2:  neighbours.append((y + 2, x))
            if len(neighbours):
                y_,x_ = neighbours[rand(0, len(neighbours) - 1)]
                if Z[y_, x_] == 0:
                    Z[y_, x_] = 1
                    Z[y_ + (y - y_) // 2, x_ + (x - x_) // 2] = 1
                    x, y = x_, y_
    return Z
 
pyplot.figure(figsize=(10, 5))
pyplot.imshow(maze(80, 40), cmap=pyplot.cm.binary, interpolation='nearest')
pyplot.xticks([]), pyplot.yticks([])
pyplot.show()
In [2]:
import numpy
from numpy.random import random_integers as rand
import matplotlib.pyplot as pyplot

class Cell:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.backtrack = [0,0,0,0] #N,E,S,W
        self.solution = [0,0,0,0]
        self.walls = [1,1,1,1]
        self.border = [0,0,0,0]
        self.visited = False
        
    def drawCell(self):
        if self.walls[0] == 1:
            pyplot.hlines(y=self.y, xmin=self.x, xmax=self.x+1, linewidth=1, color='b')
        if self.walls[1] == 1:
            pyplot.vlines(x=self.x+1, ymin=self.y, ymax=self.y+1, linewidth=1, color='b')
        if self.walls[2] == 1:
            pyplot.hlines(y=self.y+1, xmin=self.x, xmax=self.x+1, linewidth=1, color='b')    
        if self.walls[3] == 1:
            pyplot.vlines(x=self.x, ymin=self.y, ymax=self.y+1, linewidth=1, color='b')
        
    def setupBorder(self,xmax,ymax):
        if self.y == 0: #N borders
            self.border[0] = 1
        if self.x == xmax: #E borders
            self.border[1] = 1
        if self.y == ymax: #S borders
            self.border[2] = 1
        if self.x == 0: #W borders
            self.border[3] = 1
        
 
def maze(width=16, height=12):
    # Build cells' fill
    shape = (height, width)
    Z = numpy.zeros(shape, dtype=bool)
    
    # Initialize 2D cell arrray
    cells = [[0 for y in xrange(0,height)] for x in xrange(0,width)] 
    # Initialize all walls (all present)
    for y in xrange(0,height):
        for x in xrange(0,width):
            c = Cell(x,y)
            c.setupBorder(width-1, height-1)
            cells[x][y] = c
        
    # Setup Cell Stack
    stack = []
    num_total = width*height
    num_visited = 0 #keep track of total no. of cells visited
    # Get random starting cell
    rand_x = rand(0,width-1)
    rand_y = rand(0,height-1)
    #Z[rand_y,rand_x] = 1
    print 'Starting cell:(',rand_x,',',rand_y,')'
    current_cell = cells[rand_x][rand_y]
    num_visited += 1
    
    # DFS Algo
    while num_visited < num_total:
        neighbours_with_all_walls = checkNeighbours(cells, current_cell, current_cell.x, current_cell.y)
        n = len(neighbours_with_all_walls)
        if n > 0:
            index = rand(0,n-1)
            rand_neighbour = neighbours_with_all_walls[index]
            # knock down the wall btw current cell and chosen neighbour
            knockdownWallBtw(current_cell, rand_neighbour)
            stack.append(current_cell)
            current_cell = rand_neighbour
            num_visited += 1
        else:
            cell = stack.pop()
            current_cell = cell
            
    # Final Drawing
    for y in xrange(0,height):
        for x in xrange(0,width):
            c = cells[x][y]
            c.drawCell()
            
    # Route (given by end stack result)
    #for c in stack:
    #    pyplot.plot(c.x+0.5, c.y+0.5, linestyle='None', marker="s", color="y")
        
    # Get Solution for given start/end point
    calcSolution(cells, 0, 0, width-1, height-1)
            
    return Z

def checkNeighbours(cells, current_cell, x, y):
    neighbours = []
    if current_cell.border[0] == 0: #top
        nt = cells[x][y-1]
        if nt.walls == [1,1,1,1]:
            neighbours.append(nt)
    if current_cell.border[1] == 0: #right
        nr = cells[x+1][y]
        if nr.walls == [1,1,1,1]:
            neighbours.append(nr)
    if current_cell.border[2] == 0: #bottom
        nb = cells[x][y+1]
        if nb.walls == [1,1,1,1]:
            neighbours.append(nb)
    if current_cell.border[3] == 0: #left
        nl = cells[x-1][y]
        if nl.walls == [1,1,1,1]:
            neighbours.append(nl)
    return neighbours

def knockdownWallBtw(cell, nbr):
    #compare N,E,S,W direction to discern wall direction
    if nbr.y == cell.y-1:
        cell.walls[0] = 0
        nbr.walls[2] = 0   
        return
    if nbr.x == cell.x+1:
        cell.walls[1] = 0
        nbr.walls[3] = 0
        return
    if nbr.y == cell.y+1:
        cell.walls[2] = 0
        nbr.walls[0] = 0
        return
    if nbr.x == cell.x-1:
        cell.walls[3] = 0
        nbr.walls[1] = 0
        return

# Gets the maze solution route for any given start/end point
def calcSolution(cells, startx, starty, endx, endy):
    start_cell = cells[startx][starty]
    end_cell = cells[endx][endy]
    
    # DFS again...
    stack = []
    current_cell = start_cell
    current_cell.visited = True
    while current_cell != end_cell:
        # get random possible neighbour
        neighbours = getAllNeighboursNotYetVisited(cells, current_cell)
        n = len(neighbours)
        if n > 0:
            index = rand(0,n-1)
            rand_neighbour = neighbours[index]
            rand_neighbour.visited = True
            stack.append(current_cell)
            current_cell = rand_neighbour
        else: # dead end, backtrack
            cell = stack.pop()
            current_cell = cell
            
    # Plot solution
    for c in stack:
        pyplot.plot(c.x+0.5, c.y+0.5, linestyle='None', marker="s", color="g")
    pyplot.plot(start_cell.x+0.5, start_cell.y+0.5, linestyle='None', marker="*", color="y", markersize=20)
    pyplot.plot(end_cell.x+0.5, end_cell.y+0.5, linestyle='None', marker="*", color="r", markersize=20)
        
def getAllNeighboursNotYetVisited(cells, c):
    neighbours = []
    if c.border[0] == 0 and c.walls[0] == 0:
        n = cells[c.x][c.y-1]
        if not n.visited:
            neighbours.append(n)
    if c.border[1] == 0 and c.walls[1] == 0:
        n = cells[c.x+1][c.y]
        if not n.visited:
            neighbours.append(n)
    if c.border[2] == 0 and c.walls[2] == 0:
        n = cells[c.x][c.y+1]
        if not n.visited:
            neighbours.append(n)
    if c.border[3] == 0 and c.walls[3] == 0:
        n = cells[c.x-1][c.y]
        if not n.visited:
            neighbours.append(n)
    return neighbours
 
pyplot.figure(figsize=(10, 5))
pyplot.imshow(maze(16, 12), cmap=pyplot.cm.binary, interpolation='nearest')
#pyplot.xticks([]), pyplot.yticks([])
pyplot.axis([0,16,12,0])
pyplot.show()
Starting cell:( 13 , 3 )
In [100]: