Maze Runner 2D
This two-dimensional maze runner shows the player a top-down, bird’s-eye view of a maze file you create in a text editor, such as the IDE you use to write your .py files. Using the WASD keys, the player can move up, left, down, and right, respectively, to navigate the @ symbol toward the exit marked by the X character.
To make a maze file, open a text editor and create the following pattern. Don’t type the numbers along the top and left side; they are only there for reference:
123456789
1 #########
2 #S# # # #
3 #########
4 # # # # #
5 #########
6 # # # # #
7 #########
8 # # # #E#
9 #########
The # characters represent walls, the S marks the start, and the E marks the exit. The # characters in bold represent walls that you can remove to form your maze. Don’t remove the walls at odd-numbered columns and odd-numbered rows, and don’t remove the borders of the maze. When you’re done, save the maze as a .txt (text) file. It could look something like this:
#########
#S # #
# ### # #
# # # #
# ##### #
# # #
### # # #
# #E#
#########
Of course, this is a simple maze. You can make maze files of any size as long as they have an odd number of rows and columns. Be sure it’ll still fit on the screen, though! You can also download maze files from https://invpy.com/mazes/.
maze_runner_2d.py
1"""Maze Runner 2D, by Al Sweigart al@inventwithpython.com
2Move around a maze and try to escape. Maze files are generated by
3mazemakerrec.py.
4This code is available at https://nostarch.com/big-book-small-python-programming
5Tags: large, game, maze"""
6
7import sys, os
8
9# Maze file constants:
10WALL = '#'
11EMPTY = ' '
12START = 'S'
13EXIT = 'E'
14
15PLAYER = '@' # (!) Try changing this to '+' or 'o'.
16BLOCK = chr(9617) # Character 9617 is '░'
17
18
19def displayMaze(maze):
20 # Display the maze:
21 for y in range(HEIGHT):
22 for x in range(WIDTH):
23 if (x, y) == (playerx, playery):
24 print(PLAYER, end='')
25 elif (x, y) == (exitx, exity):
26 print('X', end='')
27 elif maze[(x, y)] == WALL:
28 print(BLOCK, end='')
29 else:
30 print(maze[(x, y)], end='')
31 print() # Print a newline after printing the row.
32
33
34print('''Maze Runner 2D, by Al Sweigart al@inventwithpython.com
35
36(Maze files are generated by mazemakerrec.py)''')
37
38# Get the maze file's filename from the user:
39while True:
40 print('Enter the filename of the maze (or LIST or QUIT):')
41 filename = input('> ')
42
43 # List all the maze files in the current folder:
44 if filename.upper() == 'LIST':
45 print('Maze files found in', os.getcwd())
46 for fileInCurrentFolder in os.listdir():
47 if (fileInCurrentFolder.startswith('maze') and
48 fileInCurrentFolder.endswith('.txt')):
49 print(' ', fileInCurrentFolder)
50 continue
51
52 if filename.upper() == 'QUIT':
53 sys.exit()
54
55 if os.path.exists(filename):
56 break
57 print('There is no file named', filename)
58
59# Load the maze from a file:
60mazeFile = open(filename)
61maze = {}
62lines = mazeFile.readlines()
63playerx = None
64playery = None
65exitx = None
66exity = None
67y = 0
68for line in lines:
69 WIDTH = len(line.rstrip())
70 for x, character in enumerate(line.rstrip()):
71 assert character in (WALL, EMPTY, START, EXIT), 'Invalid character at column {}, line {}'.format(x + 1, y + 1)
72 if character in (WALL, EMPTY):
73 maze[(x, y)] = character
74 elif character == START:
75 playerx, playery = x, y
76 maze[(x, y)] = EMPTY
77 elif character == EXIT:
78 exitx, exity = x, y
79 maze[(x, y)] = EMPTY
80 y += 1
81HEIGHT = y
82
83assert playerx != None and playery != None, 'No start in maze file.'
84assert exitx != None and exity != None, 'No exit in maze file.'
85
86while True: # Main game loop.
87 displayMaze(maze)
88
89 while True: # Get user move.
90 print(' W')
91 print('Enter direction, or QUIT: ASD')
92 move = input('> ').upper()
93
94 if move == 'QUIT':
95 print('Thanks for playing!')
96 sys.exit()
97
98 if move not in ['W', 'A', 'S', 'D']:
99 print('Invalid direction. Enter one of W, A, S, or D.')
100 continue
101
102 # Check if the player can move in that direction:
103 if move == 'W' and maze[(playerx, playery - 1)] == EMPTY:
104 break
105 elif move == 'S' and maze[(playerx, playery + 1)] == EMPTY:
106 break
107 elif move == 'A' and maze[(playerx - 1, playery)] == EMPTY:
108 break
109 elif move == 'D' and maze[(playerx + 1, playery)] == EMPTY:
110 break
111
112 print('You cannot move in that direction.')
113
114 # Keep moving in this direction until you encounter a branch point.
115 if move == 'W':
116 while True:
117 playery -= 1
118 if (playerx, playery) == (exitx, exity):
119 break
120 if maze[(playerx, playery - 1)] == WALL:
121 break # Break if we've hit a wall.
122 if (maze[(playerx - 1, playery)] == EMPTY
123 or maze[(playerx + 1, playery)] == EMPTY):
124 break # Break if we've reached a branch point.
125 elif move == 'S':
126 while True:
127 playery += 1
128 if (playerx, playery) == (exitx, exity):
129 break
130 if maze[(playerx, playery + 1)] == WALL:
131 break # Break if we've hit a wall.
132 if (maze[(playerx - 1, playery)] == EMPTY
133 or maze[(playerx + 1, playery)] == EMPTY):
134 break # Break if we've reached a branch point.
135 elif move == 'A':
136 while True:
137 playerx -= 1
138 if (playerx, playery) == (exitx, exity):
139 break
140 if maze[(playerx - 1, playery)] == WALL:
141 break # Break if we've hit a wall.
142 if (maze[(playerx, playery - 1)] == EMPTY
143 or maze[(playerx, playery + 1)] == EMPTY):
144 break # Break if we've reached a branch point.
145 elif move == 'D':
146 while True:
147 playerx += 1
148 if (playerx, playery) == (exitx, exity):
149 break
150 if maze[(playerx + 1, playery)] == WALL:
151 break # Break if we've hit a wall.
152 if (maze[(playerx, playery - 1)] == EMPTY
153 or maze[(playerx, playery + 1)] == EMPTY):
154 break # Break if we've reached a branch point.
155
156 if (playerx, playery) == (exitx, exity):
157 displayMaze(maze)
158 print('You have reached the exit! Good job!')
159 print('Thanks for playing!')
160 sys.exit()