Find the Way!
Maze Explorer
Design mazes with a grid of numbers, walk them tile by tile, collect keys to open doors, and race a ghost that hunts you. Grid logic powers Pac-Man, Zelda and roguelikes, learn it here.
Design mazes with a grid of numbers, walk them tile by tile, collect keys to open doors, and race a ghost that hunts you. Grid logic powers Pac-Man, Zelda and roguelikes, learn it here.
import pygameimport pygame, pygame.init()pygame.init(), the window and the while runningwhile running game loop. If you're starting here or need that template, grab it in one click: Episode 1 full template โ ยท Python Cheatsheet โDraw a full maze from a list-of-lists, 0 floor, 1 wall.
TILE = 40
maze = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1],
[1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1],
[1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1],
[1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1],
[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1],
# ... 12 rows total, design your own!
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
]
for row in range(len(maze)):
for col in range(len(maze[0])):
if maze[row][col] == 1:
pygame.draw.rect(screen, (90, 90, 100),
(col*TILE, row*TILE, TILE, TILE))TILE = 40
maze = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1],
[1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1],
[1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1],
[1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1],
[1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1],
# ... 12 rows total, design your own!
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
]
for row in range(len(maze)):
for col in range(len(maze[0])):
if maze[row][col] == 1:
pygame.draw.rect(screen, (90, 90, 100),
(col*TILE, row*TILE, TILE, TILE))
Move the player around the grid with walls that actually block.
p_row, p_col = 1, 1
# in the event loop:
if event.type == pygame.KEYDOWN:
r, c = p_row, p_col
if event.key == pygame.K_UP: r -= 1
if event.key == pygame.K_DOWN: r += 1
if event.key == pygame.K_LEFT: c -= 1
if event.key == pygame.K_RIGHT: c += 1
if maze[r][c] == 0:
p_row, p_col = r, cp_row, p_col = 1, 1
# in the event loop:
if event.type == pygame.KEYDOWN:
r, c = p_row, p_col
if event.key == pygame.K_UP: r -= 1
if event.key == pygame.K_DOWN: r += 1
if event.key == pygame.K_LEFT: c -= 1
if event.key == pygame.K_RIGHT: c += 1
if maze[r][c] == 0:
p_row, p_col = r, c
if mazeif maze]]] == ] == :
p_row, p_col = r, c:
p_row, p_col = r, c
Collect keys to pass doors, inventory logic on a grid.
keys_held = 0
# replace the move check:
target = maze[r][c]
if target == 0 or target == 2 or (target == 3 and keys_held > 0):
p_row, p_col = r, c
if target == 2:
keys_held += 1
maze[r][c] = 0
elif target == 3:
keys_held -= 1
maze[r][c] = 0keys_held = 0
# replace the move check:
target = maze[r][c]
if target == 0 or target == 2 or (target == 3 and keys_held > 0):
p_row, p_col = r, c
if target == 2:
keys_held += 1
maze[r][c] = 0
elif target == 3:
keys_held -= 1
maze[r][c] = 0
Add a ghost that chases the player through the maze.
g_row, g_col = 10, 18
ghost_timer = 0
ghost_timer += 1
if ghost_timer >= 30:
ghost_timer = 0
dr = p_row - g_row
dc = p_col - g_col
if abs(dr) > abs(dc):
step_r, step_c = (1 if dr > 0 else -1), 0
else:
step_r, step_c = 0, (1 if dc > 0 else -1)
if maze[g_row + step_r][g_col + step_c] == 0:
g_row += step_r
g_col += step_cg_row, g_col = 10, 18
ghost_timer = 0
ghost_timer += 1
if ghost_timer >= 30:
ghost_timer = 0
dr = p_row - g_row
dc = p_col - g_col
if abs(dr) > abs(dc):
step_r, step_c = (1 if dr > 0 else -1), 0
else:
step_r, step_c = 0, (1 if dc > 0 else -1)
if maze[g_row + step_r][g_col + step_c] == 0:
g_row += step_r
g_col += step_c
dr = p_row - g_row
dc = p_col - g_col
if dr = p_row - g_row
dc = p_col - g_col
if (dr) > abs(dc):
step_r = 1 if dr > (dr) > abs(dc):
step_r = 1 if dr > else -1 else -1
Complete the game loop: an exit to win, a ghost-touch to lose, R to retry.
state = "PLAY"
if (g_row, g_col) == (p_row, p_col):
state = "LOSE"
if maze[p_row][p_col] == 4:
state = "WIN"
# reset on R:
maze = [row[:] for row in start_maze]
p_row, p_col, g_row, g_col = 1, 1, 10, 18
keys_held = 0
state = "PLAY"state = "PLAY"
if (g_row, g_col) == (p_row, p_col):
state = "LOSE"
if maze[p_row][p_col] == 4:
state = "WIN"
# reset on R:
maze = [row[:] for row in start_maze]
p_row, p_col, g_row, g_col = 1, 1, 10, 18
keys_held = 0
state = "PLAY"
Chain several mazes together and learn what makes a maze FUN.
levels = [maze1, maze2, maze3]
current = 0
def load_level(i):
global maze, p_row, p_col, g_row, g_col, keys_held
maze = [row[:] for row in levels[i]]
p_row, p_col = 1, 1
g_row, g_col = 10, 18
keys_held = 0
# on reaching the exit:
current += 1
if current < len(levels):
load_level(current)
else:
state = "ESCAPED"levels = [maze1, maze2, maze3]
current = 0
def load_level(i):
global maze, p_row, p_col, g_row, g_col, keys_held
maze = [row[:] for row in levels[i]]
p_row, p_col = 1, 1
g_row, g_col = 10, 18
keys_held = 0
# on reaching the exit:
current += 1
if current < len(levels):
load_level(current)
else:
state = "ESCAPED"
current += 1
if current < current += 1
if current < (levels):
(levels):
(current)
else:
state = "ESCAPED"(current)
else:
state = "ESCAPED"
A grid maze drawn from a list of lists, tile-by-tile movement blocked by walls, keys and locked doors, a chasing ghost, win/lose states, and two chained levels ending in a YOU ESCAPED banner , one file. Both mazes are solvable. Save it as game.pygame.py, run python game.pypython game.py, and play. Stuck on a step? Compare your file against this.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 480))
pygame.display.set_caption("Maze Escape")
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 32)
big_font = pygame.font.SysFont(None, 64)
TILE = 40
# 0 floor, 1 wall, 2 key, 3 door, 4 exit
maze1 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
]
maze2 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
]
levels = [maze1, maze2]
STARTS = [((1, 1), (1, 18)), ((1, 1), (5, 1))] # (player, ghost) per level
current = 0
maze = None
p_row = p_col = g_row = g_col = 0
keys_held = 0
ghost_timer = 0
state = "PLAY"
def load_level(i):
global maze, p_row, p_col, g_row, g_col, keys_held, ghost_timer
maze = [row[:] for row in levels[i]] # deep copy row by row
(pr, pc), (gr, gc) = STARTS[i]
p_row, p_col = pr, pc
g_row, g_col = gr, gc
keys_held = 0
ghost_timer = 0
load_level(0)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r and state != "PLAY":
current = 0
load_level(0)
state = "PLAY"
elif state == "PLAY":
r, c = p_row, p_col
if event.key == pygame.K_UP: r -= 1
if event.key == pygame.K_DOWN: r += 1
if event.key == pygame.K_LEFT: c -= 1
if event.key == pygame.K_RIGHT: c += 1
target = maze[r][c]
if target in (0, 2, 4) or (target == 3 and keys_held > 0):
p_row, p_col = r, c
if target == 2:
keys_held += 1
maze[r][c] = 0
elif target == 3:
keys_held -= 1
maze[r][c] = 0
if state == "PLAY":
ghost_timer += 1
if ghost_timer >= 30:
ghost_timer = 0
dr = p_row - g_row
dc = p_col - g_col
if abs(dr) > abs(dc):
step_r, step_c = (1 if dr > 0 else -1), 0
else:
step_r, step_c = 0, (1 if dc > 0 else -1)
if maze[g_row + step_r][g_col + step_c] == 0:
g_row += step_r
g_col += step_c
if (g_row, g_col) == (p_row, p_col):
state = "LOSE"
elif maze[p_row][p_col] == 4:
current += 1
if current < len(levels):
load_level(current)
else:
state = "ESCAPED"
# draw
screen.fill((16, 18, 28))
for row in range(len(maze)):
for col in range(len(maze[0])):
t = maze[row][col]
colour = None
if t == 1: colour = (90, 90, 100)
elif t == 2: colour = (255, 209, 102)
elif t == 3: colour = (150, 90, 50)
elif t == 4: colour = (77, 217, 224)
if colour:
pygame.draw.rect(screen, colour, (col*TILE, row*TILE, TILE, TILE))
pygame.draw.rect(screen, (255, 119, 0), (p_col*TILE+5, p_row*TILE+5, TILE-10, TILE-10))
pygame.draw.rect(screen, (230, 230, 245), (g_col*TILE+5, g_row*TILE+5, TILE-10, TILE-10))
screen.blit(font.render("Keys: " + str(keys_held) + " Level " + str(current+1), True, (255, 255, 255)), (12, 8))
if state != "PLAY":
text = {"LOSE": "THE GHOST GOT YOU", "ESCAPED": "YOU ESCAPED!"}.get(state, "LEVEL CLEAR")
msg = big_font.render(text, True, (255, 209, 102))
screen.blit(msg, msg.get_rect(center=(400, 235)))
sub = font.render("Press R to play again", True, (255, 255, 255))
screen.blit(sub, sub.get_rect(center=(400, 290)))
pygame.display.flip()
clock.tick(60)
pygame.quit()import pygame
pygame.init()
screen = pygame.display.set_mode((800, 480))
pygame.display.set_caption("Maze Escape")
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 32)
big_font = pygame.font.SysFont(None, 64)
TILE = 40
# 0 floor, 1 wall, 2 key, 3 door, 4 exit
maze1 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
]
maze2 = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,4,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
]
levels = [maze1, maze2]
STARTS = [((1, 1), (1, 18)), ((1, 1), (5, 1))] # (player, ghost) per level
current = 0
maze = None
p_row = p_col = g_row = g_col = 0
keys_held = 0
ghost_timer = 0
state = "PLAY"
def load_level(i):
global maze, p_row, p_col, g_row, g_col, keys_held, ghost_timer
maze = [row[:] for row in levels[i]] # deep copy row by row
(pr, pc), (gr, gc) = STARTS[i]
p_row, p_col = pr, pc
g_row, g_col = gr, gc
keys_held = 0
ghost_timer = 0
load_level(0)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r and state != "PLAY":
current = 0
load_level(0)
state = "PLAY"
elif state == "PLAY":
r, c = p_row, p_col
if event.key == pygame.K_UP: r -= 1
if event.key == pygame.K_DOWN: r += 1
if event.key == pygame.K_LEFT: c -= 1
if event.key == pygame.K_RIGHT: c += 1
target = maze[r][c]
if target in (0, 2, 4) or (target == 3 and keys_held > 0):
p_row, p_col = r, c
if target == 2:
keys_held += 1
maze[r][c] = 0
elif target == 3:
keys_held -= 1
maze[r][c] = 0
if state == "PLAY":
ghost_timer += 1
if ghost_timer >= 30:
ghost_timer = 0
dr = p_row - g_row
dc = p_col - g_col
if abs(dr) > abs(dc):
step_r, step_c = (1 if dr > 0 else -1), 0
else:
step_r, step_c = 0, (1 if dc > 0 else -1)
if maze[g_row + step_r][g_col + step_c] == 0:
g_row += step_r
g_col += step_c
if (g_row, g_col) == (p_row, p_col):
state = "LOSE"
elif maze[p_row][p_col] == 4:
current += 1
if current < len(levels):
load_level(current)
else:
state = "ESCAPED"
# draw
screen.fill((16, 18, 28))
for row in range(len(maze)):
for col in range(len(maze[0])):
t = maze[row][col]
colour = None
if t == 1: colour = (90, 90, 100)
elif t == 2: colour = (255, 209, 102)
elif t == 3: colour = (150, 90, 50)
elif t == 4: colour = (77, 217, 224)
if colour:
pygame.draw.rect(screen, colour, (col*TILE, row*TILE, TILE, TILE))
pygame.draw.rect(screen, (255, 119, 0), (p_col*TILE+5, p_row*TILE+5, TILE-10, TILE-10))
pygame.draw.rect(screen, (230, 230, 245), (g_col*TILE+5, g_row*TILE+5, TILE-10, TILE-10))
screen.blit(font.render("Keys: " + str(keys_held) + " Level " + str(current+1), True, (255, 255, 255)), (12, 8))
if state != "PLAY":
text = {"LOSE": "THE GHOST GOT YOU", "ESCAPED": "YOU ESCAPED!"}.get(state, "LEVEL CLEAR")
msg = big_font.render(text, True, (255, 209, 102))
screen.blit(msg, msg.get_rect(center=(400, 235)))
sub = font.render("Press R to play again", True, (255, 255, 255))
screen.blit(sub, sub.get_rect(center=(400, 290)))
pygame.display.flip()
clock.tick(60)
pygame.quit()