PyMaze
Normally this would be a very simple example of a game, maybe even in Season 1. However, if it is used there only introduce the very simple maze algorithms!
main.py
from Window import Window from Game import Game def main(): window = Window() window.setLogo("logo32x32.png") window.setCaption("Maze Game by Appledog") window.setSize(800, 600) window.setFont("PxPlus_IBM_VGA_8x16-2x.ttf", 32) game = Game(window) game.start() if __name__ == "__main__": main()
As you can see from this code, this is going to be a pygame terminal framework game. We're going to use a 2x wide (40 column) font for this for aesthetic purposes.
Game.py
Standard, but there are some changes to draw(), update() and so forth. Also observe the changes to the game data at the start of the class.
import random import pygame from Maze import Maze class Game: def __init__(self, window): self.window = window self.screen = window.screen self.font = window.font self.logo = window.logo # Game Data self.FPS = 60 self.clock = pygame.time.Clock() self.maze = Maze(19, 14, 30, 30) self.maze.binary_tree_maze() self.maze.cwidth = 32 self.maze.cheight = 32 self.px = 1 self.py = 1 self.tx = random.randint(0, self.maze.width) self.ty = random.randint(0, self.maze.height) def start(self): while True: self.checkEvents() self.update() self.draw() self.clock.tick(self.FPS) def update(self): if self.px == self.tx and self.py == self.ty: print("YOU WIN!") self.quit() def draw(self): self.screen.fill((0, 0, 0)) # Clear the screen. self.maze.draw(self.screen) self.drawText(self.tx, self.ty, "X", "gold") self.drawText(self.px, self.py, "@", "gray") pygame.display.flip() # update the display. def checkEvents(self): for event in pygame.event.get(): # Window Quit Event if event.type == pygame.QUIT: self.quit() return # Keyboard Events if event.type == pygame.KEYDOWN: if event.key == pygame.K_q: self.quit() elif event.key == pygame.K_LEFT: if not self.maze.get_wall(self.px, self.py, 'west'): self.px = self.px - 1 elif event.key == pygame.K_RIGHT: if not self.maze.get_wall(self.px, self.py, 'east'): self.px = self.px + 1 elif event.key == pygame.K_UP: if not self.maze.get_wall(self.px, self.py, 'north'): self.py = self.py - 1 elif event.key == pygame.K_DOWN: if not self.maze.get_wall(self.px, self.py, 'south'): self.py = self.py + 1 def drawText(self, at_x, at_y, text, color): text_surface = self.font.render(text, False, color) x = self.window.fontwidth * at_x y = self.window.fontheight * at_y self.screen.blit(text_surface, (x+2, y+2)) def quit(self): quit() exit()
Window.py
Unchanged.
Cell.py
class Cell: def __init__(self): self.north = True self.east = True self.west = True self.south = True self.wall_color = "gray"
Just a simple class to store the info about walls.
Maze.py
The work is done here. Note the requirement for class Cell (shown above):
import random import pygame from Cell import Cell class Maze: def __init__(self, w, h, cw, ch): self.width = w self.height = h self.cwidth = cw self.cheight = ch self.map = [[Cell() for _ in range(w)] for _ in range(h)] def get_wall(self, x, y, d): if d == 'north' and self.map[y][x].north: return True elif d == 'south' and self.map[y][x].south: return True elif d == 'west' and self.map[y][x].west: return True elif d == 'east' and self.map[y][x].east: return True # fail false. return False def set_wall(self, x, y, d, s): if d == "north": self.map[y][x].north = s if y > 0: self.map[y-1][x].north = s elif d == "east": self.map[y][x].east = s if x < self.width: self.map[y][x+1].west = s elif d == "west": self.map[y][x].west = s if x > 0: self.map[y][x-1].east = s elif d == "south": self.map[y][x].south = s if y < self.width: self.map[y+1][x].north = s else: print("unknown wall position") quit() exit() def draw(self, screen): line_color = "gray" for y in range(self.height): for x in range(self.width): c = self.map[y][x] ax = 2 + x * self.cwidth ay = 2 + y * self.cheight bx = ax + self.cwidth by = ay + self.cheight if c.north: pygame.draw.line(screen, line_color, (ax, ay), (bx, ay)) if c.south: pygame.draw.line(screen, line_color, (ax, by), (bx, by)) if c.west: pygame.draw.line(screen, line_color, (ax, ay), (ax, by)) if c.east: pygame.draw.line(screen, line_color, (bx, ay), (bx, by)) def binary_tree_maze(self): for x in range(self.width): for y in range(self.height): if x == self.width - 1 and y == self.height - 1: continue elif x == self.width - 1: self.set_wall(x, y, "south", False) elif y == self.height - 1: self.set_wall(x, y, "east", False) else: if random.choice([True, False]): self.set_wall(x, y, "east", False) else: self.set_wall(x, y, "south", False)
Binary Tree Maze Algorithm
The binary tree maze algorithm is a simple algorithm for generating mazes. It is often used in computer graphics, game development, and robotics.
The binary tree maze algorithm works by iteratively deciding whether to create passages to the east or south, resulting in a maze with paths that resemble a binary tree structure. The randomness adds variability to the generated mazes. This algorithm is relatively easy to understand, making it suitable for beginners exploring maze generation algorithms and basic grid-based world generation.
- Iteration over Cells:
- The code iterates over each cell in the maze, represented by x and y coordinates.
- Corner Cells Handling:
- The algorithm checks if the current cell is at the bottom-right corner of the maze (x == self.width - 1 and y == self.height - 1). If so, it continues to the next iteration, skipping the cell. This ensures that the bottom-right cell remains open.
- If the cell is on the rightmost edge but not the bottom-right corner, a passage is opened to the south (self.set_wall(x, y, “south”, False)). This creates a path towards the bottom of the maze.
- If the cell is on the bottom edge but not the bottom-right corner, a passage is opened to the east (self.set_wall(x, y, “east”, False)). This creates a path towards the right side of the maze.
- Inner Cells:
- For inner cells (not on the right or bottom edge), a decision is made using random.choice([True, False]). This randomly chooses whether to create a passage to the east or south.
- If True, a passage is opened to the east (self.set_wall(x, y, “east”, False)).
- If False, a passage is opened to the south (self.set_wall(x, y, “south”, False)).