My issue is with my def countNeighbours(self, grid)
function. In the grid, every cell is surround by four walls making each of them rectangles. I decided to use the wrap around method where the an edge cell'
s neighbor is on the other side. This way none of the indices will be out of bounds. However now I've run into the problem where the maze pathing goes straight down and breaks. I can't comprehend why exactly.
Screenshot of the bug.
The goal was for the maze pathing to randomly visited a couple cells and destroy the walls before stopping. Then I'd move on the the backtracking step.
Here is the entire code:
import pygame
import random
pygame.init()
screenWidth = 604
screenHeight = 604
FPS = 60
# Colors
Red = (255, 0, 0)
Blue = (0, 100, 200, 50)
Green = (0, 200, 100, 50)
White = (255, 255, 255)
Black = (0, 0, 0)
# TODO: FIX THE COUNTING FUNCTION- MESSES UP THE PATHING
class Cell:
def __init__(self, i, j):
self.i = i # Row
self.j = j # Column
self.visited = False
# Checks to see if wall(s) of the cell exists
# Order: Top, Right, Bottom, Left
self.wall = [True, True, True, True]
def draw(self, surface):
x = self.i * length
y = self.j * length
# Our Path in Green
if self.visited:
pygame.draw.rect(displayWindow, Green, (x, y, length, length))
# Top Line Start Pos, End Pos
if self.wall[0]:
pygame.draw.line(displayWindow, White, (x, y), (x + length, y), 1)
# Right Line
if self.wall[1]:
pygame.draw.line(displayWindow, White, (x + length, y), (x + length, y + length), 1)
# Bottom
if self.wall[2]:
pygame.draw.line(displayWindow, White, (x + length, y + length), (x, y + length), 1)
# Left
if self.wall[3]:
pygame.draw.line(displayWindow, White, (x, y + length), (x, y), 1)
self.changed = False
# Function adds the unvisited to the cell's neighbor array and returns the next cell
def countNeighbors(self, grid):
global x, y
self.neighbors = []
top = grid[(((self.i + 1) + x) % x)][self.j]
right = grid[self.i][(((self.j + 1) + y) % y)]
bottom = grid[(((self.i - 1) + x) % x)][self.j]
left = grid[self.i][(((self.j - 1) + y) % y)]
# If the neighbor cell is unvisited add to array
if not top.visited:
self.neighbors.append(top)
if not right.visited:
self.neighbors.append(right)
if not bottom.visited:
self.neighbors.append(bottom)
if not left.visited:
self.neighbors.append(left)
# pick random unvisted cell as our next
if len(self.neighbors) > 0:
p = random.randrange(0, len(self.neighbors))
return self.neighbors[p]
# Highlights the current cell
def marker(self):
x = self.i * length
y = self.j * length
pygame.draw.rect(displayWindow, Blue, (x, y, length, length))
# Rows and Columns, length will be our width of each cell
length = 40
rows = screenWidth // length
cols = screenHeight // length
print(rows, cols)
# store cells
grid = [[]*cols]*rows
for i in range(rows):
for j in range(cols):
cell = Cell(i, j)
grid[i].append(cell)
current = grid[0][0]
x = len(grid)
y = len(grid[i])
def display(surface):
global current
for i in range(len(grid)):
for j in range(len(grid[i])):
grid[i][j].draw(surface)
# Mark first cell as visited
current.visited = True
current.marker()
# Check neighbors of current cell
nextCell = current.countNeighbors(grid)
if nextCell:
nextCell.visited = True
deleteWall(current, nextCell)
current = nextCell
def deleteWall(a, b):
# Right and Left Walls
p = a.i - b.i
if p == 1: # neighbor to the left
a.wall[3] = False
b.wall[1] = False
elif p == -1: # neighbor to the right
a.wall[1] = False
b.wall[3] = False
# Top and Bottom Walls
q = a.j - b.j
if q == 1: # neighbor above
a.wall[0] = False
b.wall[2] = False
elif q == -1: # neighbor below
a.wall[2] = False
b.wall[0] = False
displayWindow = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Maze Generator")
def main():
global FPS
FPSclock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
FPSclock.tick(FPS)
display(displayWindow)
pygame.display.update()
if __name__ == '__main__':
main()
Found the bug:
grid = [[]*cols]*rows
And the correct functions were:
def countNeighbors(self, grid):
global x, y
self.neighbors = []
# Edge Cases
# Top Cell
if self.j == 0:
self.neighbors.append(None)
else:
self.neighbors.append(grid[self.i][self.j - 1])
# Right
if self.i == x - 1:
self.neighbors.append(None)
else:
self.neighbors.append(grid[self.i + 1][self.j])
# Bottom
if self.j == y - 1:
self.neighbors.append(None)
else:
self.neighbors.append(grid[self.i][self.j + 1])
# Left
if self.i == 0:
self.neighbors.append(None)
else:
self.neighbors.append(grid[self.i - 1][self.j])
grid = []
for i in range(rows):
column = []
for j in range(cols):
cell = Cell(i, j)
column.append(cell)
grid.append(column)
def display(surface):
global current
for i in range(len(grid)):
for j in range(len(grid[i])):
grid[i][j].draw(surface)
grid[i][j].countNeighbors(grid)
current.visited = True
current.marker()
next = random.choice(current.neighbors)
if next and not next.visited:
next.visited = True
deleteWall(current, next)
current = next