CMU Coding Bootcamp
1from cmu_graphics.cmu_graphics import app, AppWrapper
2from cmu_graphics import *
3from random import randint
4from time import sleep
5from sys import exit
6
7
8def onAppStart(app_inst: AppWrapper):
9 app_inst.rows = 8
10 app_inst.cols = 10
11 app_inst.boardLeft = 25
12 app_inst.boardTop = 85
13 app_inst.boardWidth = 350
14 app_inst.boardHeight = 280
15 app_inst.cellBorderWidth = 1
16 app_inst.snake = [(randint(0, app_inst.rows - 1), randint(0, app_inst.cols - 1))]
17 app_inst.direction = [0, 0]
18 app_inst.fruit = None
19 app_inst.gameOver = False
20 app_inst.portals = [(-1, -1), (-1, -1)]
21 makePortals(app_inst)
22 app_inst.poison = None
23
24
25def makePortals(app_inst: AppWrapper):
26 while (
27 manhattenDist(app_inst.portals[0], app_inst.portals[1]) < 5
28 or distanceToWall(app_inst, app_inst.portals[0]) < 2
29 or distanceToWall(app_inst, app_inst.portals[1]) < 2
30 ):
31 app_inst.portals = [
32 (randint(0, app_inst.rows - 1), randint(0, app_inst.cols - 1)),
33 (randint(0, app_inst.rows - 1), randint(0, app_inst.cols - 1)),
34 ]
35
36
37def distanceToWall(app_inst: AppWrapper, pos):
38 return min(pos[0], app_inst.rows - pos[0] - 1, pos[1], app_inst.cols - pos[1] - 1)
39
40
41def manhattenDist(p1, p2):
42 return abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])
43
44
45def onKeyPress(app_inst: AppWrapper, key):
46 if key == "up" and not app_inst.direction[0]:
47 app_inst.direction = [-1, 0]
48 elif key == "down" and not app_inst.direction[0]:
49 app_inst.direction = [1, 0]
50 elif key == "left" and not app_inst.direction[1]:
51 app_inst.direction = [0, -1]
52 elif key == "right" and not app_inst.direction[1]:
53 app_inst.direction = [0, 1]
54 elif key == "r":
55 onAppStart(app_inst)
56 elif key == "q":
57 exit()
58 elif key == "space":
59 app_inst.gameOver = True
60
61
62def moveSnake(app_inst: AppWrapper):
63 if app_inst.gameOver:
64 return
65 head = app_inst.snake[0]
66 newHead = (
67 (head[0] + app_inst.direction[0]) % app_inst.rows,
68 (head[1] + app_inst.direction[1]) % app_inst.cols,
69 )
70 app_inst.snake.insert(0, newHead)
71 if newHead in app_inst.portals:
72 app_inst.snake[0] = app_inst.portals[1 - app_inst.portals.index(newHead)]
73 elif newHead == app_inst.poison:
74 app_inst.gameOver = True
75 if len(app_inst.snake) > 1:
76 app_inst.snake.pop()
77 for segment in app_inst.snake[1:]:
78 if app_inst.snake[0] == segment:
79 app_inst.gameOver = True
80
81
82def onStep(app_inst: AppWrapper):
83 if not app_inst.fruit:
84 makeFruit(app_inst)
85 makePoison(app_inst)
86 head = app_inst.snake[0]
87 if head == app_inst.fruit:
88 app_inst.fruit = None
89 app_inst.snake.append(app_inst.snake[-1])
90 moveSnake(app_inst)
91
92
93def getCell(app_inst: AppWrapper, pos):
94 if pos in app_inst.snake:
95 return "snake"
96 elif pos == app_inst.fruit:
97 return "fruit"
98 elif pos in app_inst.portals:
99 return "portal"
100 elif pos == app_inst.poison:
101 return "poison"
102 elif pos == None:
103 return "empty"
104 return None
105
106
107def makeFruit(app_inst: AppWrapper):
108 fruit = None
109 while getCell(app_inst, fruit) is not None:
110 fruit = (randint(0, app_inst.rows - 1), randint(0, app_inst.cols - 1))
111 app_inst.fruit = fruit
112 break
113
114
115def makePoison(app_inst: AppWrapper):
116 poison = None
117 while getCell(app_inst, poison) is not None:
118 poison = (randint(0, app_inst.rows - 1), randint(0, app_inst.cols - 1))
119 app_inst.poison = poison
120 break
121
122
123def redrawAll(app_inst: AppWrapper):
124 drawLabel("Snake!", 200, 30, size=16)
125 drawBoard(app_inst)
126 drawBoardBorder(app_inst)
127 drawFruit(app_inst)
128 drawPoison(app_inst)
129 drawPortals(app_inst)
130 drawSnake(app_inst)
131 sleep(0.1875)
132 if app_inst.gameOver:
133 drawGameOver(app_inst)
134
135
136def drawPoison(app_inst: AppWrapper):
137 if app_inst.poison is not None:
138 cellLeft, cellTop = getCellLeftTop(app_inst, *app_inst.poison)
139 cellWidth, cellHeight = getCellSize(app_inst)
140 drawCircle(
141 cellLeft + cellWidth / 2,
142 cellTop + cellHeight / 2,
143 cellWidth / 2 - 6,
144 fill="purple",
145 )
146
147
148def drawPortals(app_inst: AppWrapper):
149 for portal in app_inst.portals:
150 cellLeft, cellTop = getCellLeftTop(app_inst, portal[0], portal[1])
151 cellWidth, cellHeight = getCellSize(app_inst)
152 drawCircle(
153 cellLeft + cellWidth / 2,
154 cellTop + cellHeight / 2,
155 cellWidth / 2 - 6,
156 fill="black",
157 )
158
159
160def drawGameOver(app_inst: AppWrapper):
161 drawRect(app_inst.width / 2 - 150, app_inst.height / 2 - 50, 300, 100, fill="white")
162 drawLabel("Game Over!", app_inst.width / 2, app_inst.height / 2 - 20, size=16)
163 drawLabel(
164 f"Score: {len(app_inst.snake)-1}",
165 app_inst.width / 2,
166 app_inst.height / 2,
167 size=12,
168 )
169 drawLabel(
170 "Press R to restart", app_inst.width / 2, app_inst.height / 2 + 20, size=12
171 )
172 drawLabel("Press Q to quit", app_inst.width / 2, app_inst.height / 2 + 40, size=12)
173
174
175def drawFruit(app_inst: AppWrapper):
176 if app_inst.fruit is not None:
177 cellLeft, cellTop = getCellLeftTop(app_inst, *app_inst.fruit)
178 cellWidth, cellHeight = getCellSize(app_inst)
179 drawCircle(
180 cellLeft + cellWidth / 2,
181 cellTop + cellHeight / 2,
182 cellWidth / 2 - 8,
183 fill="red",
184 )
185
186
187def drawSnake(app_inst: AppWrapper):
188 cellWidth, cellHeight = getCellSize(app_inst)
189 for i, segment in enumerate(app_inst.snake):
190 cellLeft, cellTop = getCellLeftTop(app_inst, segment[0], segment[1])
191 color = "green" if i == 0 else "gray"
192 drawCircle(
193 cellLeft + cellWidth / 2,
194 cellTop + cellHeight / 2,
195 cellWidth / 2 - 4,
196 fill=color,
197 )
198
199
200def drawBoard(app_inst: AppWrapper):
201 for row in range(app_inst.rows):
202 for col in range(app_inst.cols):
203 drawCell(app_inst, row, col)
204
205
206def drawBoardBorder(app_inst: AppWrapper):
207 drawRect(
208 app_inst.boardLeft,
209 app_inst.boardTop,
210 app_inst.boardWidth,
211 app_inst.boardHeight,
212 fill=None,
213 border="black",
214 borderWidth=2 * app_inst.cellBorderWidth,
215 )
216
217
218def drawCell(app_inst: AppWrapper, row, col):
219 cellLeft, cellTop = getCellLeftTop(app_inst, row, col)
220 cellWidth, cellHeight = getCellSize(app_inst)
221 drawRect(
222 cellLeft,
223 cellTop,
224 cellWidth,
225 cellHeight,
226 fill=None,
227 border="gray",
228 borderWidth=app_inst.cellBorderWidth,
229 )
230
231
232def getCellLeftTop(app_inst: AppWrapper, row, col):
233 cellWidth, cellHeight = getCellSize(app_inst)
234 cellLeft = app_inst.boardLeft + col * cellWidth
235 cellTop = app_inst.boardTop + row * cellHeight
236 return (cellLeft, cellTop)
237
238
239def getCellSize(app_inst: AppWrapper):
240 cellWidth = app_inst.boardWidth / app_inst.cols
241 cellHeight = app_inst.boardHeight / app_inst.rows
242 return (cellWidth, cellHeight)
243
244
245def main():
246 runApp()
247
248
249main()