๐Ÿ My First Python Game ยท Episode 4 of 7 ยท See All Episodes
๐Ÿฐ Episode 4 ยท Improver ยท Grid-Based Logic

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.

๐Ÿ‘ถ Ages 10+ โฑ๏ธ ~1.5 Hours ๐Ÿ Python โœ“ Free
๐Ÿ—บ๏ธ Grid maps ๐Ÿšถ Tile movement ๐Ÿ—๏ธ Keys & doors ๐Ÿ‘ป Chase AI ๐ŸŽจ Level design ๐Ÿ”ข 2D lists
โญ
0 XP
Level 1
๐Ÿ”ฅ0
Your Progress 0 / 6 steps
1
๐Ÿ—บ๏ธ
The Maze Grid
A 2D list of numbers becomes a maze on screen
Active
๐ŸŽฏ
Goal for this step

Draw a full maze from a list-of-lists, 0 floor, 1 wall.

  • 1The maze is a list of lists of ints. Each tile is 40 px; a 20ร—12 grid fills 800ร—480.
  • 2Write the maze BY HAND, every row a list. You are drawing with numbers.
  • 3Nested loops convert grid โ†’ pixels: x = col*40, y = row*40.
  • 4Walls slate-grey, floor near-black. Run it and admire your maze.
game.py
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))
โœ๏ธ
Fill in the Blanks
+15 XP
maze[row][col] reads the tile at that grid position, first, then col. Pixel x comes from col ร— .
๐Ÿง 
Knowledge Check
+15 XP
Why store the maze as numbers instead of drawing rectangles by hand?
ANumbers draw faster
BThe SAME data drives drawing, collision, items and AI, one source of truth
CPygame requires lists
2
๐Ÿšถ
Tile-by-Tile Movement
Step one tile per key press, blocked by walls
Locked
๐ŸŽฏ
Goal for this step

Move the player around the grid with walls that actually block.

  • 1The playerโ€™s position is now p_row, p_col, grid coordinates, not pixels.
  • 2Use KEYDOWN events (one step per press), compute the target tile, move only if it is 0.
  • 3Draw the player at (p_col*TILE+5, p_row*TILE+5), slightly inset.
  • 4Try to walk through a wall. You cannot. That is 4 lines of collision, grid games are elegant!
game.py
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, c
โŒจ๏ธ
Code Challenge
+20 XP
Only step onto floor tiles:
game.py
if maze]] == :
    p_row, p_col = r, c
๐Ÿ’ก Hint: Look up the TARGET tile (row first) and check it is floor before committing the move.
๐Ÿง 
Knowledge Check
+15 XP
Compared to pixel collision (colliderect), grid collision isโ€ฆ
ALess accurate but simpler
BOne array lookup, perfectly accurate for tile worlds and far simpler
COnly for 3D games
3
๐Ÿ—๏ธ
Keys & Doors
Tile 2 is a key, tile 3 is a locked door
Locked
๐ŸŽฏ
Goal for this step

Collect keys to pass doors, inventory logic on a grid.

  • 1Extend the tile language: 2 = key (gold square), 3 = door (brown).
  • 2Add keys_held = 0. Stepping on a key tile: keys_held += 1, tile becomes 0.
  • 3A door tile is walkable only if keys_held > 0, walking through consumes a key and clears the tile.
  • 4Place 2 keys and 2 doors so the player must explore. Order matters, that is puzzle design.
game.py
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] = 0
โœ๏ธ
Fill in the Blanks
+15 XP
Stepping on tile 2 raises and sets the tile to . Doors need keys_held > to pass.
๐Ÿง 
Knowledge Check
+15 XP
The door consumes a key (keys_held -= 1). What design does this create?
ADoors are decoration
BResource management, two doors and one key means a real choice about which route to open
CKeys respawn
4
๐Ÿ‘ป
The Ghost
A hunter that steps toward you on a timer
Locked
๐ŸŽฏ
Goal for this step

Add a ghost that chases the player through the maze.

  • 1Ghost position: g_row, g_col, starting far from the player.
  • 2Every 30 frames the ghost takes ONE step: compare positions and move the direction that closes the bigger gap, if that tile is floor.
  • 3The ghost obeys walls too, so you can juke it around corners!
  • 4If the ghost reaches your tile โ†’ game over (next step). Draw it white-ish.
game.py
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_c
โŒจ๏ธ
Code Challenge
+20 XP
Make the ghost chase along the bigger gap:
game.py
dr = p_row - g_row
dc = p_col - g_col
if (dr) > abs(dc):
    step_r = 1 if dr >  else -1
๐Ÿ’ก Hint: Compare absolute distances to pick an axis; the sign of the difference picks the direction.
๐Ÿง 
Knowledge Check
+15 XP
The ghost moves every 30 frames but you move per key press. Who is faster?
AAlways the ghost
BA player pressing quickly outruns it, but corridors and doors slow YOU down. That tension is the game
CThey are identical
5
๐Ÿ†
Exit, Win & Lose
Reach tile 4 to escape, before the ghost reaches you
Locked
๐ŸŽฏ
Goal for this step

Complete the game loop: an exit to win, a ghost-touch to lose, R to retry.

  • 1Tile 4 = exit (green), placed far from the start, ideally behind a door.
  • 2Stepping on it โ†’ state "WIN". Ghost on your tile โ†’ state "LOSE".
  • 3Freeze movement in either state; show the message; R resets everything (positions, keys, maze copy).
  • 4Resetting the maze needs a DEEP copy of the original: [row[:] for row in start_maze], lists of lists need copying row by row!
game.py
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"
โš ๏ธ
maze = start_maze would NOT reset, both names would point at the same list. The row-by-row copy makes a true fresh maze.
โœ๏ธ
Fill in the Blanks
+15 XP
Copying a 2D list needs a copy of each , the one-liner is [row[:] for row in start_maze]. Just assigning with = only copies the .
๐Ÿง 
Knowledge Check
+15 XP
Why place the exit behind a door?
ADoors look nice
BIt forces the key hunt to matter, the maze becomes a puzzle with steps, not a sprint
CTile 4 needs tile 3
6
๐ŸŽจ
Design Your Own Levels
Multiple mazes, a level counter and design rules
Locked
๐ŸŽฏ
Goal for this step

Chain several mazes together and learn what makes a maze FUN.

  • 1Put your mazes in a list: levels = [maze1, maze2, maze3] with a current = 0 index.
  • 2Winning now advances: current += 1, load the next maze, finishing the last one shows the grand YOU ESCAPED banner.
  • 3Design rules the pros use: multiple routes (dead ends frustrate), keys visible before their doors, the ghost start far from spawn, exit NOT next to spawn.
  • 4Test each maze yourself, if you get bored walking it, redesign it. You are the level designer now.
game.py
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"
โŒจ๏ธ
Code Challenge
+20 XP
Advance to the next level, or finish the game:
game.py
current += 1
if current < (levels):
    (current)
else:
    state = "ESCAPED"
๐Ÿ’ก Hint: Compare against how many levels exist; the helper function does all the resetting.
๐Ÿง 
Knowledge Check
+15 XP
Which is the strongest maze-design rule?
AMake every corridor one tile wide
BGive players multiple routes and visible goals, frustration is not difficulty
CHide the exit next to the spawn
๐ŸŽ‰๐Ÿ†๐ŸŽฎโœจ๐ŸŽ‰
Workshop Complete!
Grids, tile movement, lock-and-key and a hunting ghost, dungeon logic mastered. Episode 5 brings back the arcade with Breakout!
0
Total XP
1
Level
0
Best Streak
0%
Accuracy
โ–ถ Episode 5: Breakout โ†’
โญ View My Progress & Certificates

This workshop was free and took many hours to build. If it helped you learn something new, consider supporting the project.

☕ Support on Ko-fi