Skip to content
Newer
Older
100644 1821 lines (1583 sloc) 66.8 KB
b68496b @djrahl first commit
authored
1 #!/usr/bin/env python
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
2 # A Snakey clone made with Pygame.
3 # Includes various fruits with different effects in regards to score,
4 # snake size, and other in-game effects.
5 # Includes various Snake AIs and game modes (Arcade, Duel, Party).
b68496b @djrahl first commit
authored
6
7 import random, pygame, sys
8 from pygame.locals import *
9
6c613da @djrahl Worked on AI; added crude apple detection.
authored
10 FPS = 12
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
11 MIN_FPS = 3
12 MAX_FPS = 60
353c181 @djrahl snake color changes based on consumption.
authored
13 FREEZING_POINT = 8 # target FPS when Blueberry (slow) is in effect.
14
15 WINDOWWIDTH = 640
16 WINDOWHEIGHT = 480
b68496b @djrahl first commit
authored
17 CELLSIZE = 20
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
18 TOP_BUFFER = CELLSIZE * 1 # displays in-game info
b68496b @djrahl first commit
authored
19 assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
20 assert (WINDOWHEIGHT - TOP_BUFFER) % CELLSIZE == 0, "Window height must be a multiple of cell size."
b68496b @djrahl first commit
authored
21 CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
22 CELLHEIGHT = int((WINDOWHEIGHT - TOP_BUFFER) / CELLSIZE)
b68496b @djrahl first commit
authored
23
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
24 # colors - (R G B)
b68496b @djrahl first commit
authored
25 WHITE = (255, 255, 255)
26 BLACK = (0, 0, 0)
27 BLUE = (0, 0, 255)
353c181 @djrahl snake color changes based on consumption.
authored
28 COBALTGREEN = (61, 145, 64)
b68496b @djrahl first commit
authored
29 DARKGRAY = (40, 40, 40)
30 FORESTGREEN = (34, 139, 34)
31 GOLDENROD = (218, 165, 32)
353c181 @djrahl snake color changes based on consumption.
authored
32 GREEN = (0, 255, 0)
33 IVORY = (205, 205, 193)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
34 ORANGE = (255, 127, 0)
353c181 @djrahl snake color changes based on consumption.
authored
35 PINK = (255, 105, 180)
b68496b @djrahl first commit
authored
36 PURPLE = (142, 56, 142)
353c181 @djrahl snake color changes based on consumption.
authored
37 RED = (255, 0, 0)
38 SLATEBLUE = (131, 111, 255)
39 YELLOW = (238, 238, 0)
40
41 BACKGROUNDCLR = BLACK
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
42 BUTTONCLR = GREEN
43 BUTTONTXT = DARKGRAY
353c181 @djrahl snake color changes based on consumption.
authored
44 BUTTONCLR_SEL = COBALTGREEN
45 BUTTONTXT_SEL = GOLDENROD
46 MESSAGECLR = GREEN
b68496b @djrahl first commit
authored
47
353c181 @djrahl snake color changes based on consumption.
authored
48 # for consistency
b68496b @djrahl first commit
authored
49 UP = 'up'
50 DOWN = 'down'
51 LEFT = 'left'
52 RIGHT = 'right'
6127227 @djrahl Added more selection for Duel Mode.
authored
53 SNAKEY = 'snakey'
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
54 LINUS = 'linus'
9850469 @djrahl changed core AI methods/algorithm.
authored
55 WIGGLES = 'wiggles'
56 GOOBER = 'goober'
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
57
6c613da @djrahl Worked on AI; added crude apple detection.
authored
58 # index of snake's head
59 HEAD = 0
b68496b @djrahl first commit
authored
60
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
61 # minimum and maximum frames fruit remains on screen - determined randomly
62 POISONTIMER = (100, 200)
63 ORANGETIMER = (35, 65)
64 RASPBERRYTIMER = (30, 45)
65 BLUEBERRYTIMER = (20, 40)
66 LEMONTIMER = (100, 100)
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
67 EGGTIMER = (40, 70)
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
68
b68496b @djrahl first commit
authored
69
70 class Snake:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
71 """
72 Snake class houses all information for a particular snake.
73 player - if snake is the player. Player snake is also referenced directly when player snake object is created.
6d8cfaf @djrahl set-up ai
authored
74 name - name of snake.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
75 alive - if snake is alive. Rather than delete, this allows snake to slowly shrink to the point of where it died.
76 coords - a list of dictionaries containing coordinates 'x' and 'y'. A special global variable HEAD (0).
77 direction - where snake moves for every game iteration ('left', 'up', etc).
78 color - body of snake's color.
79 colorBorder - outline of body.
80 growth - when a snake is to grow, this is stored in this buffer so that every game iteration can add one growth, only.
81 multiplier - all fruit eaten which cause points to be scored are multiplied by this.
82 multipliertimer - number of game iterations multiplier stays in effect.
83 score - the number of points snake has accumulated.
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
84 place - used to determine death order.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
85 """
353c181 @djrahl snake color changes based on consumption.
authored
86 def __init__(self, n=SNAKEY, c=False, colorsnake=GREEN, colorborder=COBALTGREEN):
6d8cfaf @djrahl set-up ai
authored
87 self.name = n
6127227 @djrahl Added more selection for Duel Mode.
authored
88 if self.name == SNAKEY:
89 self.player = True
90 else:
91 self.player = False
b68496b @djrahl first commit
authored
92 self.alive = True
6127227 @djrahl Added more selection for Duel Mode.
authored
93
94 if c == False:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
95 self.coords = getStartCoords(1)
6127227 @djrahl Added more selection for Duel Mode.
authored
96 else:
97 self.coords = c
98
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
99 # determine direction if length supports
100 if len(self.coords) > 1:
101 if self.coords[0]['x'] > self.coords[1]['x']:
102 self.direction = RIGHT
103 else:
104 self.direction = LEFT
105 # egg -- for now until AI direction fixed
6127227 @djrahl Added more selection for Duel Mode.
authored
106 else:
353c181 @djrahl snake color changes based on consumption.
authored
107 self.direction = LEFT
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
108
353c181 @djrahl snake color changes based on consumption.
authored
109 self.color = {'red': 0, 'green': 0, 'blue': 0}
110 self.updateColor({'red': colorsnake[0], 'green': colorsnake[1], 'blue': colorsnake[2]})
4ae7881 @djrahl Fixed grid and snake color changes.
authored
111 self.colorCurrent = self.color
353c181 @djrahl snake color changes based on consumption.
authored
112
113 self.colorBorder = {'red': 0, 'green': 0, 'blue': 0}
114 self.updateColorBorder({'red': colorborder[0], 'green': colorborder[1], 'blue': colorborder[2]})
4ae7881 @djrahl Fixed grid and snake color changes.
authored
115 self.colorBorderCurrent = self.colorBorder
353c181 @djrahl snake color changes based on consumption.
authored
116
b68496b @djrahl first commit
authored
117 self.growth = 0
118 self.multiplier = 1
119 self.multipliertimer = 0
120 self.score = 0
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
121 self.place = False
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
122 self.scored = True
123 self.fruitEaten = {'apple':0, 'poison':0, 'orange':0, 'raspberry':0,
124 'blueberry':0, 'lemon':0, 'egg':0}
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
125
126 def updateScore(self, points_input):
127 """
128 This updates score of snake, factoring multiplier.
129 """
130 self.score = self.score + (points_input * self.multiplier)
131
132 def updateGrowth(self, growth_input):
133 """
134 This updates growth "owed" to snake, allowing amount to stack.
135 """
136 self.growth = self.growth + growth_input
137
138 def updateMultiplier(self, multiplier_input, timer_input):
139 """
140 This updates multiplier value and time (game iterations) multiplier is active. Only time stacks.
141 """
142 # multiplier value does not stack, but time does
143 self.multiplier = multiplier_input
144 self.multipliertimer = self.multipliertimer + timer_input
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
145
353c181 @djrahl snake color changes based on consumption.
authored
146 def updateColor(self, change):
147 """
148 Adjusts color of snake.
149 Argument (change) is dictionary.
150 Factors in maximums and minimums.
151 """
152 for color in change:
153 if self.color.has_key(color):
154 if change[color] > 0:
155 if self.color[color] + change[color] > 255:
156 self.color[color] = 255
157 else:
158 self.color[color] = self.color[color] + change[color]
159 elif change[color] < 0:
160 if self.color[color] + change[color] < 0:
161 self.color[color] = 0
162 else:
163 self.color[color] = self.color[color] + change[color]
164
165 def updateColorBorder(self, change):
166 """
167 Adjusts border color of snake.
168 Argument (change) is dictionary.
169 Factors in maximums and minimums.
170 """
171 for color in change:
172 if self.colorBorder.has_key(color):
173 if change[color] > 0:
174 if self.colorBorder[color] + change[color] > 255:
175 self.colorBorder[color] = 255
176 else:
177 self.colorBorder[color] = self.colorBorder[color] + change[color]
178 elif change[color] < 0:
179 if self.colorBorder[color] + change[color] < 0:
180 self.colorBorder[color] = 0
181 else:
182 self.colorBorder[color] = self.colorBorder[color] + change[color]
183
184 def setColorCurrent(self, color):
185 """
186 Takes tuple (color) and sets current color.
187 """
188 self.colorCurrent = {'red': color[0], 'green': color[1], 'blue': color[2]}
189
190 def setColorBorderCurrent(self, color):
191 """
192 Takes tuple (color) and sets current color.
193 """
194 self.colorBorderCurrent = {'red': color[0], 'green': color[1], 'blue': color[2]}
195
196 def getColor(self):
197 """
198 Returns tuple of snake color.
199 """
200 return (self.color['red'], self.color['green'], self.color['blue'])
201
202 def getColorCurrent(self):
203 """
204 Returns tuple of snake color, currently.
205 """
206 return (self.colorCurrent['red'], self.colorCurrent['green'], self.colorCurrent['blue'])
207
208 def getColorBorder(self):
209 """
210 Returns tuple of snake color, border.
211 """
212 return (self.colorBorder['red'], self.colorBorder['green'], self.colorBorder['blue'])
213
214 def getColorBorderCurrent(self):
215 """
216 Returns tuple of snake color, current border.
217 """
218 return (self.colorBorderCurrent['red'], self.colorBorderCurrent['green'], self.colorBorderCurrent['blue'])
219
220 def resetColor(self):
221 """
222 Sets current color to color.
223 """
224 self.colorCurrent = self.color
225
226 def resetColorBorder(self):
227 """
228 Sets current color to color.
229 """
230 self.colorBorderCurrent = self.colorBorder
231
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
232 def getPlace(self, totaldead, totalscored):
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
233 """
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
234 Returns a string containing the 'place' of a snake (longest lasting = 1st)
235 If game aborted early, will grant all living snakes '1st (alive)'
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
236 """
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
237 totalalive = totalscored - totaldead
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
238
239 # snake not dead
240 if self.place == False:
241 return '1st (alive)'
242 # if not aborted early
243 elif totalalive == 0:
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
244 if self.place == totalscored:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
245 return '1st'
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
246 elif self.place + 1 == totalscored:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
247 return '2nd'
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
248 elif self.place + 2 == totalscored:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
249 return '3rd'
250 else:
251 return 'last'
252 # aborted early; factor in living snakes
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
253 elif self.place == totalscored - totalalive:
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
254 return '2nd'
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
255 elif self.place + 1 == totalscored - totalalive:
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
256 return '3rd'
257 else:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
258 return 'last'
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
259
260 def checkCoords(self, x, y):
261 """
262 Returns True if snake (head) matches (x,y) coordinates provided.
263 Will always return False if coordinates < 1.
264 """
265 if len(self.coords) > 0:
266 if self.coords[HEAD]['x'] == x and self.coords[HEAD]['y'] == y:
267 return True
268 return False
269
270 def getCoords(self, axis):
271 """
272 Returns x or y (axis) coordinates of head of snake.
273 Will always return False if coordinates < 1.
274 """
275 if len(self.coords) > 0:
276 return self.coords[HEAD][axis]
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
277
278 def boundsCollision(self):
279 """
280 This returns True if snake (head) is ever out of grid parameters.
281 """
6d8cfaf @djrahl set-up ai
authored
282 # check if out of bounds -- offset on on 'y' for buffer.
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
283 if self.getCoords('x') == -1 or \
284 self.getCoords('x') == CELLWIDTH or \
285 self.getCoords('y') == -1 + (TOP_BUFFER / CELLSIZE) or \
286 self.getCoords('y') == CELLHEIGHT + (TOP_BUFFER / CELLSIZE):
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
287 return True
288 else:
289 return False
290
291 def snakeCollision(self, snake):
292 """
293 This returns True if snake (head) collides with any part of a given snake (outside of own head if checking against self).
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
294 Will always return False if coordinates of self or snake < 1.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
295 """
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
296 if len(self.coords) > 0 and len(snake.coords) > 0:
297 if self is snake:
298 # exclude head if checked against self
299 for snakebody in snake.coords[1:]:
300 if snakebody['x'] == self.coords[HEAD]['x'] and \
301 snakebody['y'] == self.coords[HEAD]['y']:
302 return True
303 else:
304 for snakebody in snake.coords:
305 if snakebody['x'] == self.coords[HEAD]['x'] and \
306 snakebody['y'] == self.coords[HEAD]['y']:
307 return True
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
308 # no collision
309 return False
310
311 def fruitCollision(self, fruit):
312 """
313 This returns True if snake (head) has collided with a given fruit.
314 """
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
315 if self.getCoords('x') == fruit.coords['x'] and \
316 self.getCoords('y') == fruit.coords['y']:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
317 return True
318 else:
319 return False
320
c9dd311 @djrahl added tron(y) mode.
authored
321 def move(self, trailing=False):
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
322 """
323 This will update coords for snake, moving it one cell in given direction.
324 It also factors in and updates growth if any growth is "owed" snake (one per game iteration).
325 If snake is dead, will only remove the last segment of snake and ignore direction / not move snake.
326 """
327 if self.alive:
328 # delete last segment first.
329 if self.growth < 0:
330 self.growth = self.growth + 1
331 if len(self.coords) > 3:
332 # implement negative growth by removing last two segments
333 del self.coords[-2:]
334 else:
335 # snake is too short -- remove last segment as normal
336 del self.coords[-1]
337 elif self.growth > 0:
338 # implement positive growth by not deleting last segment
c9dd311 @djrahl added tron(y) mode.
authored
339 self.growth = self.growth - 1
340 elif trailing == False:
341 # no growth factor, delete last segment if trailing is off
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
342 del self.coords[-1]
343
344 # determine new head coordinates by direction
345 if self.direction == UP:
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
346 newhead = {'x': self.getCoords('x'),
347 'y': self.getCoords('y') - 1}
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
348 elif self.direction == DOWN:
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
349 newhead = {'x': self.getCoords('x'),
350 'y': self.getCoords('y') + 1}
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
351 elif self.direction == LEFT:
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
352 newhead = {'x': self.getCoords('x') - 1,
353 'y': self.getCoords('y')}
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
354 elif self.direction == RIGHT:
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
355 newhead = {'x': self.getCoords('x') + 1,
356 'y': self.getCoords('y')}
c9dd311 @djrahl added tron(y) mode.
authored
357
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
358 # insert new head segment
359 self.coords.insert(HEAD, newhead)
360
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
361 # dead snake -- remove last segment
362 elif len(self.coords) > 0:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
363 del self.coords[-1]
364
365 def drawSnake(self):
366 """
367 Responsible for drawing snake image to screen.
368 """
369 for coord in self.coords:
370 x = coord['x'] * CELLSIZE
371 y = coord['y'] * CELLSIZE
372 snakeSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
353c181 @djrahl snake color changes based on consumption.
authored
373 pygame.draw.rect(DISPLAYSURF, self.getColorBorderCurrent(), snakeSegmentRect)
374 snakeInnerSegmentRect = pygame.Rect(x + 3, y + 3, CELLSIZE - 6, CELLSIZE - 6)
375 pygame.draw.rect(DISPLAYSURF, self.getColorCurrent(), snakeInnerSegmentRect)
6d8cfaf @djrahl set-up ai
authored
376
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
377 def drawScore(self, position, allsnake):
6d8cfaf @djrahl set-up ai
authored
378 """
379 Responsible for drawing snake score to screen.
380 """
353c181 @djrahl snake color changes based on consumption.
authored
381 scoreSurf = BASICFONT.render('%s: %s' % (self.name, self.score), True, self.getColorCurrent())
6d8cfaf @djrahl set-up ai
authored
382 scoreRect = scoreSurf.get_rect()
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
383 # get number of snakes in allsnake that will be scored.
384 totalscored = 0
385 for snake in allsnake:
386 if snake.scored == True:
387 totalscored = totalscored + 1
388 scoreRect.topleft = (getPosition(position, allsnake, totalscored), 1)
6d8cfaf @djrahl set-up ai
authored
389 DISPLAYSURF.blit(scoreSurf, scoreRect)
390
391
392 class Opponent(Snake):
393 """
394 Derived from Snake class, this adds functionality for determining direction.
395 """
9850469 @djrahl changed core AI methods/algorithm.
authored
396 def __init__(self, n='bot', c=False, sc=COBALTGREEN, sb=GOLDENROD, r=20, p=10, a=-15, g=[50,-10,30,20,35,100]):
6127227 @djrahl Added more selection for Duel Mode.
authored
397 Snake.__init__(self, n, c, sc, sb)
6d8cfaf @djrahl set-up ai
authored
398 self.avoidBoundaries = True
9850469 @djrahl changed core AI methods/algorithm.
authored
399 self.depthPerception = 20
c134769 @djrahl fixed key input bug
authored
400 self.randomness = r
6d8cfaf @djrahl set-up ai
authored
401 self.preferSameDirection = p
9850469 @djrahl changed core AI methods/algorithm.
authored
402 self.avoidSnake = a
403 self.goal = {'apple': g[0], 'poison': g[1], 'orange': g[2], 'raspberry': g[3], 'blueberry': g[4], 'lemon': g[5]}
6d8cfaf @djrahl set-up ai
authored
404
405 def updateDirection(self, grid):
9850469 @djrahl changed core AI methods/algorithm.
authored
406 """
407 Responsible for determining opponent's direction choice.
408 Takes one argument - grid representation of playing board. Copied and marked as cells are 'explored'
409 Neighboring
410 """
411 # copy grid to snake -- this will allow cells already searched to be marked 'visited'
412 self.grid = grid
413
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
414 # all directions have value adjusted -- reset
9850469 @djrahl changed core AI methods/algorithm.
authored
415 self.nextDirection = {LEFT:0, RIGHT:0, UP:0, DOWN:0}
6d8cfaf @djrahl set-up ai
authored
416
417 # coords of own snake head
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
418 x = self.getCoords('x')
419 y = self.getCoords('y')
6d8cfaf @djrahl set-up ai
authored
420
421 # opposite direction kills snake
422 if self.direction == LEFT:
9850469 @djrahl changed core AI methods/algorithm.
authored
423 self.nextDirection[RIGHT] = self.nextDirection[RIGHT] - 1000
6d8cfaf @djrahl set-up ai
authored
424 elif self.direction == RIGHT:
9850469 @djrahl changed core AI methods/algorithm.
authored
425 self.nextDirection[LEFT] = self.nextDirection[LEFT] - 1000
6d8cfaf @djrahl set-up ai
authored
426 elif self.direction == UP:
9850469 @djrahl changed core AI methods/algorithm.
authored
427 self.nextDirection[DOWN] = self.nextDirection[DOWN] - 1000
6d8cfaf @djrahl set-up ai
authored
428 elif self.direction == DOWN:
9850469 @djrahl changed core AI methods/algorithm.
authored
429 self.nextDirection[UP] = self.nextDirection[UP]- 1000
6d8cfaf @djrahl set-up ai
authored
430
431 # avoid boundaries
432 if self.avoidBoundaries == True:
433 if x == 0:
9850469 @djrahl changed core AI methods/algorithm.
authored
434 self.nextDirection[LEFT] = self.nextDirection[LEFT] - 1000
6d8cfaf @djrahl set-up ai
authored
435 if x == CELLWIDTH - 1:
9850469 @djrahl changed core AI methods/algorithm.
authored
436 self.nextDirection[RIGHT] = self.nextDirection[RIGHT] - 1000
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
437 if y == (TOP_BUFFER / CELLSIZE):
9850469 @djrahl changed core AI methods/algorithm.
authored
438 self.nextDirection[UP] = self.nextDirection[UP] - 1000
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
439 if y == CELLHEIGHT + (TOP_BUFFER / CELLSIZE) - 1:
9850469 @djrahl changed core AI methods/algorithm.
authored
440 self.nextDirection[DOWN] = self.nextDirection[DOWN] - 1000
6d8cfaf @djrahl set-up ai
authored
441
442 # prefer same direction
9850469 @djrahl changed core AI methods/algorithm.
authored
443 self.nextDirection[self.direction] = self.nextDirection[self.direction] + self.preferSameDirection
6d8cfaf @djrahl set-up ai
authored
444
445 # avoid immediate snakes
446 if grid.has_key((x-1,y)) and (grid[(x-1,y)] == 'snake'):
9850469 @djrahl changed core AI methods/algorithm.
authored
447 self.nextDirection[LEFT] = self.nextDirection[LEFT] - 1000
6d8cfaf @djrahl set-up ai
authored
448 if grid.has_key((x+1,y)) and (grid[(x+1,y)] == 'snake'):
9850469 @djrahl changed core AI methods/algorithm.
authored
449 self.nextDirection[RIGHT] = self.nextDirection[RIGHT] - 1000
6d8cfaf @djrahl set-up ai
authored
450 if grid.has_key((x,y-1)) and (grid[(x,y-1)] == 'snake'):
9850469 @djrahl changed core AI methods/algorithm.
authored
451 self.nextDirection[UP] = self.nextDirection[UP] - 1000
6c613da @djrahl Worked on AI; added crude apple detection.
authored
452 if grid.has_key((x,y+1)) and (grid[(x,y+1)] == 'snake'):
9850469 @djrahl changed core AI methods/algorithm.
authored
453 self.nextDirection[DOWN] = self.nextDirection[DOWN] - 1000
454
455 # 'look' to neighboring squares for possible snakes and fruits
456 self.look(x, y, self.depthPerception)
6c613da @djrahl Worked on AI; added crude apple detection.
authored
457
458 # favor direction of apple -- this approach will need to be replaced eventually
9850469 @djrahl changed core AI methods/algorithm.
authored
459 #for cell in grid:
460 # if grid[cell] == 'apple':
461 # # get x and y differences and favor direction of apple inversely proportionate to distance
462 # x_difference = cell[0] - x
463 # y_difference = cell[1] - y
464 # if x_difference > 0:
465 # nextDirection[RIGHT] = nextDirection[RIGHT] + (CELLWIDTH - x_difference)
466 # else:
467 # nextDirection[LEFT] = nextDirection[LEFT] + (CELLWIDTH - x_difference)
468 # if y_difference < 0:
469 # nextDirection[UP] = nextDirection[UP] + (CELLHEIGHT - y_difference)
470 # else:
471 # nextDirection[DOWN] = nextDirection[DOWN] + (CELLHEIGHT - y_difference)
6d8cfaf @djrahl set-up ai
authored
472
473 # factor in randomness
9850469 @djrahl changed core AI methods/algorithm.
authored
474 for d in self.nextDirection:
475 self.nextDirection[d] = self.nextDirection[d] + random.randint(0,self.randomness)
6d8cfaf @djrahl set-up ai
authored
476
477 # report if debugging
478 if DEBUG == True:
479 print self.name
9850469 @djrahl changed core AI methods/algorithm.
authored
480 print self.nextDirection
6d8cfaf @djrahl set-up ai
authored
481
482 # update snake direction to direction with highest score
9850469 @djrahl changed core AI methods/algorithm.
authored
483 self.direction = max(self.nextDirection, key=self.nextDirection.get)
484
485 def look(self, x, y, depth):
486 """
487 recursively looks in all directions unless depth is exhausted.
488 visited coords are ignored.
489 coords containing a snake are affected by avoidSnake variable
490 """
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
491 #if DEBUG == True:
492 # print 'look for %s at (%s, %s)- depth %s' % (self.name, x, y, depth)
9850469 @djrahl changed core AI methods/algorithm.
authored
493 if depth < 1:
494 return
495 elif self.grid.has_key((x,y)):
496 if self.grid[(x,y)] == 'visited':
497 return
498 elif self.grid[(x,y)] == 'snake':
499 if DEBUG == True:
500 print '..snake:'
501 self.influenceDirection(x, y, self.avoidSnake)
502 self.grid[(x,y)] = 'visited'
503 self.look(x-1, y, depth -1)
504 self.look(x+1, y, depth -1)
505 self.look(x, y+1, depth -1)
506 self.look(x, y-1, depth -1)
507 elif self.grid[(x,y)] != 0: # implied fruit
508 fruit = self.grid[(x,y)]
509 if DEBUG == True:
510 print '..fruit: %s' % (fruit)
511 self.influenceDirection(x, y, self.goal[fruit])
512 self.grid[(x,y)] = 'visited'
513 self.look(x-1, y, depth -1)
514 self.look(x+1, y, depth -1)
515 self.look(x, y+1, depth -1)
516 self.look(x, y-1, depth -1)
517 else: #empty cell
518 self.grid[(x,y)] = 'visited'
519 self.look(x-1, y, depth -1)
520 self.look(x+1, y, depth -1)
521 self.look(x, y+1, depth -1)
522 self.look(x, y-1, depth -1)
523 else: #bound collision
524 return
525
526 def influenceDirection(self, x, y, base):
527 """
528 Finds difference between (x,y) coord and point of origin.
529 Direction is then altered by 'base' amount, decayed 1 per distance from.
530 """
531 if DEBUG == True:
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
532 print '....%s (%s, %s)-->' % (self.nextDirection, x, y)
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
533 xdiff = self.getCoords('x') - x
534 ydiff = self.getCoords('y') - y
9850469 @djrahl changed core AI methods/algorithm.
authored
535 if xdiff > 0: # positive = left
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
536 if (base - xdiff > 0 and base > 0) or (base - xdiff < 0 and base < 0):
9850469 @djrahl changed core AI methods/algorithm.
authored
537 self.nextDirection[LEFT] = self.nextDirection[LEFT] + base - xdiff
538 elif xdiff < 0: # negative = right
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
539 if (base + xdiff > 0 and base > 0) or (base + xdiff < 0 and base < 0):
540 self.nextDirection[RIGHT] = self.nextDirection[RIGHT] + base + xdiff
9850469 @djrahl changed core AI methods/algorithm.
authored
541 if ydiff > 0: # positive = up
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
542 if (base - ydiff > 0 and base > 0) or (base - ydiff < 0 and base < 0):
9850469 @djrahl changed core AI methods/algorithm.
authored
543 self.nextDirection[UP] = self.nextDirection[UP] + base - ydiff
544 elif ydiff < 0: # negative = down
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
545 if (base + ydiff > 0 and base > 0) or (base + ydiff < 0 and base < 0):
546 self.nextDirection[DOWN] = self.nextDirection[DOWN] + base + ydiff
9850469 @djrahl changed core AI methods/algorithm.
authored
547 if DEBUG == True:
548 print '....%s' % (self.nextDirection)
6d8cfaf @djrahl set-up ai
authored
549
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
550 def getPlace(self, totaldead, totalsnakes):
551 return Snake.getPlace(self, totaldead, totalsnakes)
353c181 @djrahl snake color changes based on consumption.
authored
552
553 def updateColor(self, change):
554 Snake.updateColor(self, change)
555
556 def updateColorBorder(self, change):
557 Snake.updateColorBorder(self, change)
558
559 def setColorCurrent(self, color):
560 Snake.setColorCurrent(self, color)
561
562 def setColorBorderCurrent(self, color):
563 Snake.setColorBorderCurrent(self, color)
564
565 def getColor(self):
566 return Snake.getColor(self)
567
568 def getColorCurrent(self):
569 return Snake.getColorCurrent(self)
570
571 def getColorBorder(self):
572 return Snake.getColorBorder(self)
573
574 def getColorBorderCurrent(self):
575 return Snake.getColorBorderCurrent(self)
576
577 def resetColor(self):
578 Snake.resetColor(self)
579
580 def resetColorBorder(self):
581 Snake.resetColorBorder(self)
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
582
6d8cfaf @djrahl set-up ai
authored
583 def updateScore(self, points_input):
584 Snake.updateScore(self, points_input)
585
586 def updateGrowth(self, growth_input):
587 Snake.updateGrowth(self, growth_input)
588
589 def updateMultiplier(self, multiplier_input, timer_input):
590 Snake.updateMultiplier(self, multiplier_input, timer_input)
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
591
592 def checkCoords(self, x, y):
593 return Snake.checkCoords(self, x, y)
594
595 def getCoords(self, axis):
596 return Snake.getCoords(self, axis)
6d8cfaf @djrahl set-up ai
authored
597
598 def boundsCollision(self):
599 return Snake.boundsCollision(self)
600
601 def snakeCollision(self, snake):
602 return Snake.snakeCollision(self, snake)
603
604 def fruitCollision(self, fruit):
605 return Snake.fruitCollision(self, fruit)
606
c9dd311 @djrahl added tron(y) mode.
authored
607 def move(self, trailing):
608 Snake.move(self, trailing)
6d8cfaf @djrahl set-up ai
authored
609
610 def drawSnake(self):
611 Snake.drawSnake(self)
612
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
613 def drawScore(self, position, allsnake):
614 Snake.drawScore(self, position, allsnake)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
615
b68496b @djrahl first commit
authored
616
617 class Fruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
618 """
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
619 Fruit class houses all information for fruit objects.
620 Base class is not meant to be instantiated, but rather provide base methods shared by all fruit.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
621 """
622 def __init__(self):
623 self.timer = 0
624
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
625 def getRandomLocation(self, allfruit, allsnake, game):
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
626 """
627 Returns random coordinates (for fruit to be placed). Ensures that coordinates are not occupied by fruit or snake head.
628 Will keep fruit away from edges (outside 20%) if in an "easy mode" determined in Tally object.
629 """
b68496b @djrahl first commit
authored
630 while True:
631 conflict = False
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
632 if game.checkEasyTrigger():
b68496b @djrahl first commit
authored
633 x = random.randint(int(CELLWIDTH/5), CELLWIDTH - int(CELLWIDTH/5) - 1)
634 y = random.randint(int(CELLHEIGHT/5), CELLHEIGHT - int(CELLHEIGHT/5) - 1)
635 else:
636 x = random.randint(0, CELLWIDTH - 1)
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
637 y = random.randint((TOP_BUFFER / CELLSIZE), CELLHEIGHT - 1)
b68496b @djrahl first commit
authored
638 # ensure coordinates are not already occupied by fruit
639 for fruit in allfruit:
640 if fruit.coords['x'] == x and fruit.coords['y'] == y:
641 conflict = True
642 # ensure coordinates are not already occupied by snake head
643 for snake in allsnake:
f1b179b @djrahl added accessor/mutator w/ safety guards for coords in Snake class.
authored
644 if snake.getCoords('x') == x and snake.getCoords('y') == y:
b68496b @djrahl first commit
authored
645 conflict = True
646 if conflict == False:
647 return {'x':x, 'y':y}
648
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
649 def updateTimer(self):
650 """
651 Returns true and decrements if there is still time left for fruit to be on screen.
652 """
b68496b @djrahl first commit
authored
653 if self.timer > 0:
654 self.timer = self.timer - 1
655 return True
656 else:
657 return False
658
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
659 def drawFruit(self):
660 """
661 Responsible for drawing fruit image to screen.
662 """
663 x = self.coords['x'] * CELLSIZE
664 y = self.coords['y'] * CELLSIZE
665 fruitRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
666 pygame.draw.rect(DISPLAYSURF, self.color, fruitRect)
667
668
669 class Apple(Fruit):
670 """
671 Apples are a unique fruit in that they never leave the screen and once one is eaten, it is always replaced with another.
672 They also add points and one growth
673 """
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
674 def __init__(self, allfruit, allsnake, game):
675 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, game)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
676 self.color = RED
677 self.points = 10
678 self.growth = 1
679
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
680 def isEaten(self, snake, game):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
681 snake.fruitEaten['apple'] = snake.fruitEaten['apple'] + 1
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
682 game.fruitEaten['apple'] = game.fruitEaten['apple'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
683 snake.updateScore(self.points)
684 snake.updateGrowth(self.growth)
353c181 @djrahl snake color changes based on consumption.
authored
685 snake.updateColor({'red': 6, 'green': -3, 'blue': -3})
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
686
687 def drawFruit(self):
688 Fruit.drawFruit(self)
689
690
691 class Poison(Fruit):
692 """
693 Poison will shorten a snake (by adding a negative growth value) and reduce points.
694 """
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
695 def __init__(self, allfruit, allsnake, game):
696 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, game)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
697 self.timer = random.randint(POISONTIMER[0], POISONTIMER[1])
698 self.color = GREEN
699 self.points = -25
700 self.growth = -3
701
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
702 def isEaten(self, snake, game):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
703 snake.fruitEaten['poison'] = snake.fruitEaten['poison'] + 1
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
704 game.fruitEaten['poison'] = game.fruitEaten['poison'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
705 snake.updateScore(self.points)
706 snake.updateGrowth(self.growth)
353c181 @djrahl snake color changes based on consumption.
authored
707 snake.updateColor({'red': -20, 'green': 20, 'blue': -5})
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
708
709 def updateTimer(self):
710 return Fruit.updateTimer(self)
711
712 def drawFruit(self):
713 Fruit.drawFruit(self)
714
715
716 class Orange(Fruit):
717 """
718 Orange will grow snake substantially and are worth points.
719 """
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
720 def __init__(self, allfruit, allsnake, game):
721 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, game)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
722 self.timer = random.randint(ORANGETIMER[0], ORANGETIMER[1])
723 self.color = ORANGE
724 self.points = 50
725 self.growth = 3
726
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
727 def isEaten(self, snake, game):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
728 snake.fruitEaten['orange'] = snake.fruitEaten['orange'] + 1
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
729 game.fruitEaten['orange'] = game.fruitEaten['orange'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
730 snake.updateScore(self.points)
731 snake.updateGrowth(self.growth)
353c181 @djrahl snake color changes based on consumption.
authored
732 snake.updateColor({'red': 10, 'green': 8, 'blue': -10})
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
733
734 def updateTimer(self):
735 return Fruit.updateTimer(self)
736
737 def drawFruit(self):
738 Fruit.drawFruit(self)
739
740
741 class Raspberry(Fruit):
742 """
743 Raspberry will set snake's multiplier to two for a period of time.
744 """
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
745 def __init__(self, allfruit, allsnake, game):
746 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, game)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
747 self.timer = random.randint(RASPBERRYTIMER[0], RASPBERRYTIMER[1])
748 self.color = PURPLE
749 self.multiplier = 2
750 self.multipliertimer = 100
751
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
752 def isEaten(self, snake, game):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
753 snake.fruitEaten['raspberry'] = snake.fruitEaten['raspberry'] + 1
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
754 game.fruitEaten['raspberry'] = game.fruitEaten['raspberry'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
755 snake.updateMultiplier(self.multiplier, self.multipliertimer)
353c181 @djrahl snake color changes based on consumption.
authored
756 snake.updateColor({'red': 12, 'green': -15, 'blue': 13})
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
757
758 def updateTimer(self):
759 return Fruit.updateTimer(self)
760
761 def drawFruit(self):
762 Fruit.drawFruit(self)
763
764
765 class Blueberry(Fruit):
766 """
767 Blueberry will reduce the frame rate (slowing down game iterations) for a period of time.
768 It is also worth a lot of points.
769 """
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
770 def __init__(self, allfruit, allsnake, game):
771 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, game)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
772 self.timer = random.randint(BLUEBERRYTIMER[0], BLUEBERRYTIMER[1])
773 self.color = BLUE
774 self.score = 100
a734fdb @djrahl Added snake choices for duel mode.
authored
775 self.slowtimer = 80
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
776
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
777 def isEaten(self, snake, game):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
778 snake.fruitEaten['blueberry'] = snake.fruitEaten['blueberry'] + 1
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
779 game.fruitEaten['blueberry'] = game.fruitEaten['blueberry'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
780 snake.updateScore(self.score)
353c181 @djrahl snake color changes based on consumption.
authored
781 snake.updateColor({'red': -20, 'green': -15, 'blue': 60})
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
782
783 def updateTimer(self):
784 return Fruit.updateTimer(self)
785
786 def drawFruit(self):
787 Fruit.drawFruit(self)
788
789
790 class Lemon(Fruit):
ff23b3c @djrahl Worked on AI.
authored
791 """
4ae7881 @djrahl Fixed grid and snake color changes.
authored
792 TBD... currently worth 1000 points.
793 """
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
794 def __init__(self, allfruit, allsnake, game):
795 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, game)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
796 self.timer = random.randint(LEMONTIMER[0], LEMONTIMER[1])
797 self.color = YELLOW
798 self.score = 1000
799
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
800 def isEaten(self, snake, game):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
801 snake.fruitEaten['lemon'] = snake.fruitEaten['lemon'] + 1
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
802 game.fruitEaten['lemon'] = game.fruitEaten['lemon'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
803 snake.updateScore(self.score)
353c181 @djrahl snake color changes based on consumption.
authored
804 snake.updateColor({'blue': -20})
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
805
806 def updateTimer(self):
807 return Fruit.updateTimer(self)
808
809 def drawFruit(self):
810 Fruit.drawFruit(self)
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
811
812
813 class Egg(Fruit):
814 """
815 Eggs spawn another snake if not eaten.
816 """
817 def __init__(self, allfruit, allsnake, game):
818 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, game)
819 self.timer = random.randint(EGGTIMER[0], EGGTIMER[1])
353c181 @djrahl snake color changes based on consumption.
authored
820 self.color = GOLDENROD
821 self.colorBorder = WHITE
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
822 self.points = 500
823 self.growth = 1
353c181 @djrahl snake color changes based on consumption.
authored
824 self.radius = CELLSIZE / 2
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
825
826 def isEaten(self, snake, game):
827 snake.fruitEaten['egg'] = snake.fruitEaten['egg'] + 1
828 game.fruitEaten['egg'] = game.fruitEaten['egg'] + 1
829 snake.updateScore(self.points)
830 snake.updateGrowth(self.growth)
353c181 @djrahl snake color changes based on consumption.
authored
831 snake.updateColor({'red': -35, 'green': -30, 'blue': -25})
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
832
833 def updateTimer(self):
353c181 @djrahl snake color changes based on consumption.
authored
834 """
835 Also adjusts radius size depending on time remaining.
836 """
837 if self.timer < (EGGTIMER[0] + EGGTIMER[1]) * 2 / 3:
838 self.radius = CELLSIZE / 3
839 if self.timer < (EGGTIMER[0] + EGGTIMER[1]) / 2:
840 self.radius = CELLSIZE / 4
841 if self.timer < (EGGTIMER[0] + EGGTIMER[1]) / 3:
842 self.radius = CELLSIZE / 5
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
843 return Fruit.updateTimer(self)
844
845 def isHatched(self, allsnake):
846 """
847 Add new snake with coords as coords of fruit, and growth of 3.
848 Snake is not scored (name and score does not appear).
849 """
850 junior = Opponent('junior', [{'x':self.coords['x'] , 'y':self.coords['y']}], PINK, GREEN, 10, 10, -15, [30, 5, 60, 30, 35, 100])
851 junior.growth = 3
852 junior.scored = False
853 allsnake.append(junior)
854
855 def drawFruit(self):
856 """
857 Responsible for drawing image to screen.
858 """
859 x = self.coords['x'] * CELLSIZE
860 y = self.coords['y'] * CELLSIZE
353c181 @djrahl snake color changes based on consumption.
authored
861 xNext = (self.coords['x'] + 1) * CELLSIZE
862 yNext = (self.coords['y'] + 1) * CELLSIZE
863 center = ((xNext + x) / 2, (yNext + y) / 2)
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
864 fruitRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
353c181 @djrahl snake color changes based on consumption.
authored
865 pygame.draw.rect(DISPLAYSURF, self.colorBorder, fruitRect)
866 pygame.draw.circle(DISPLAYSURF, self.color, center, self.radius)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
867
868
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
869 class GameData:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
870 """
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
871 Responsible for dynamics for a particular game instance.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
872 fruitEaten - a dictionary containing a numeric tally of each fruit eaten.
873 speedTrigger - the frequency (based on apples consumed) in which gamespeed is increased by one.
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
874 bonusFruitTrigger - the frequency (based on apples consumed) in which a bonus game is launched.
875 bonusSnakeTrigger - the frequency (based on apples consumed) in which an egg is placed on screen.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
876 easyTrigger - a threshold (apples consumed); once reached fruit can be placed anywhere on screen (as opposed to away from edges).
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
877 currentplace - the current 'place' of snake. When snake has died.
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
878 apples - number of apples on screen.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
879 """
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
880 def __init__(self, st=20, bft=10, et=20, a=1):
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
881 self.fruitEaten = {'apple':0, 'poison':0, 'orange':0, 'raspberry':0,
882 'blueberry':0, 'lemon':0, 'egg':0}
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
883 self.speedTrigger = st
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
884 self.bonusFruitTrigger = bft
885 self.bonusSnakeTrigger = False
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
886 self.easyTrigger = et
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
887 self.currentplace = 1
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
888 self.apples = a
889 self.basespeed = FPS
890 self.currentspeed = self.basespeed
891 self.slowtimer = 0
c9dd311 @djrahl added tron(y) mode.
authored
892 self.trailing = False
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
893 self.poisonDrop = 4
894 self.orangeDrop = 5
895 self.raspberryDrop = 6
353c181 @djrahl snake color changes based on consumption.
authored
896 self.blueberryDrop = 25
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
897 self.lemonDrop = False
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
898 self.eggDrop = 12
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
899
900 def checkSpeedTrigger(self):
901 """
902 Returns true if number of apples consumed modulo speedTrigger equals zero.
903 """
904 if self.fruitEaten['apple'] % self.speedTrigger == 0:
905 return True
906 else:
907 return False
908
909 def checkBonusTrigger(self):
910 """
911 Returns true if number of apples consumed modulo bonusTrigger equals zero.
912 """
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
913 if self.fruitEaten['apple'] % self.bonusFruitTrigger == 0:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
914 return True
915 else:
916 return False
917
918 def checkEasyTrigger(self):
919 """
920 Returns true if number of apples consumed is less than or equal to easyTrigger.
921 """
922 if self.fruitEaten['apple'] <= self.easyTrigger:
923 return True
924 else:
925 return False
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
926
927 def checkSnakeDeath(self, allsnake):
928 """
929 Returns true if there are no more living snakes.
930 Sets place of snake if recently died.
931 """
932 gameover = True
933 for snake in allsnake:
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
934 if snake.scored == True:
935 if snake.alive == True:
936 gameover = False
937 elif snake.place == False:
938 snake.place = self.currentplace
939 self.currentplace = self.currentplace + 1
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
940 return gameover
941
942 def updateBaseSpeed(self, value):
943 """
944 Updates basespeed by value inputted.
945 Checks against parameters
946 """
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
947 if (self.basespeed + value > MIN_FPS) and \
948 (self.basespeed + value < MAX_FPS):
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
949 self.basespeed = self.basespeed + value
950 self.currentspeed = self.basespeed
951
952 def updateCurrentSpeed(self, goal=False, force=False):
953 """
954 Adjusts currentspeed one towards goal.
955 Goal defaults to basespeed.
956 Optional 'force' will set currentspeed to goal instead.
957 """
958 if goal == False:
959 goal = self.basespeed
960
961 if force != False:
962 self.currentspeed = goal
963 else:
964 if self.currentspeed < goal:
965 self.currentspeed = self.currentspeed + 1
966 elif self.currentspeed > goal:
967 self.currentspeed = self.currentspeed - 1
968
969 def checkSlowTimer(self):
970 """
971 Returns true if slowtimer is greater than 0.
972 """
973 if self.slowtimer > 0:
974 return True
975 else:
976 return False
977
978 def updateSlowTimer(self):
979 """
980 Decrements slowtimer by one
981 """
982 self.slowtimer = self.slowtimer - 1
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
983
984 def runDrop(self, allfruit, allsnake):
985 """
986 Adds fruit randomly to screen.
987 If newapple is turned on, replaces apple that was eaten.
988 """
989 # chance of poison drop
990 if self.poisonDrop != False and random.randint(1,self.poisonDrop) == 1:
991 p = Poison(allfruit, allsnake, self)
992 allfruit.append(p)
993 # chance of orange drop
994 if self.orangeDrop != False and random.randint(1,self.orangeDrop) == 1:
995 o = Orange(allfruit, allsnake, self)
996 allfruit.append(o)
997 # chance of raspberry drop
998 if self.raspberryDrop != False and random.randint(1,self.raspberryDrop) == 1:
999 r = Raspberry(allfruit, allsnake, self)
1000 allfruit.append(r)
1001 # chance of blueberry drop
1002 if self.blueberryDrop != False and random.randint(1,self.blueberryDrop) == 1:
1003 b = Blueberry(allfruit, allsnake, self)
1004 allfruit.append(b)
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1005 # chance of lemon drop
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1006 if self.lemonDrop != False and random.randint(1,self.lemonDrop) == 1:
1007 l = Lemon(allfruit, allsnake, self)
1008 allfruit.append(l)
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1009 # chance of egg drop
1010 if self.eggDrop != False and random.randint(1,self.eggDrop) == 1:
1011 e = Egg(allfruit, allsnake, self)
1012 allfruit.append(e)
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1013 # create new apple
1014 a = Apple(allfruit, allsnake, self)
1015 allfruit.append(a)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1016
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1017 def runBonusFruit(self, allfruit, allsnake):
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1018 """
1019 Returns a list containing fruit (as strings) to be added to game from bonus game.
1020 An integer (determined randomly between typeMin and typeMax) corresponds to bonus game run.
1021 A basic set-up would randomly choose between 1 and 10; 6 through 10 initiating a fruit specific bonus.
1022 Default will contain an assortment of fruit.
1023 """
1024 bonus = []
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1025 type = random.randint(1, 20)
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1026
1027 # based on bonus type, create fruits
1028 if type == 1:
353c181 @djrahl snake color changes based on consumption.
authored
1029 counter = random.randint(5,15)
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1030 while counter > 0:
1031 bonus.append('egg')
1032 counter = counter - 1
1033 elif type == 2 or type == 3:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1034 counter = random.randint(20,35)
1035 while counter > 0:
1036 bonus.append('poison')
1037 counter = counter - 1
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1038 elif type == 4 or type == 5:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1039 counter = random.randint(20,35)
1040 while counter > 0:
1041 bonus.append('orange')
1042 counter = counter - 1
353c181 @djrahl snake color changes based on consumption.
authored
1043 elif type == 6:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1044 counter = random.randint(20,35)
1045 while counter > 0:
1046 bonus.append('raspberry')
1047 counter = counter - 1
353c181 @djrahl snake color changes based on consumption.
authored
1048 elif type == 7:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1049 counter = random.randint(20,30)
1050 while counter > 0:
1051 bonus.append('blueberry')
1052 counter = counter - 1
353c181 @djrahl snake color changes based on consumption.
authored
1053 # default bonus
1054 else:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1055 counter = random.randint(0,3)
1056 while counter > 0:
1057 bonus.append('poison')
1058 counter = counter - 1
1059 counter = random.randint(5,20)
1060 while counter > 0:
1061 bonus.append('orange')
1062 counter = counter - 1
1063 counter = random.randint(1,4)
1064 while counter > 0:
1065 bonus.append('raspberry')
1066 counter = counter - 1
1067 counter = random.randint(0,2)
1068 while counter > 0:
1069 bonus.append('blueberry')
1070 counter = counter - 1
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1071
1072 # add fruits
1073 for bonusfruit in bonus:
1074 if bonusfruit == 'poison':
1075 f = Poison(allfruit, allsnake, self)
1076 elif bonusfruit == 'orange':
1077 f = Orange(allfruit, allsnake, self)
1078 elif bonusfruit == 'raspberry':
1079 f = Raspberry(allfruit, allsnake, self)
1080 elif bonusfruit == 'blueberry':
1081 f = Blueberry(allfruit, allsnake, self)
1082 elif bonusfruit == 'lemon':
1083 f = Lemon(allfruit, allsnake, self)
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1084 elif bonusfruit == 'egg':
1085 f = Egg(allfruit, allsnake, self)
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1086 allfruit.append(f)
1087
b68496b @djrahl first commit
authored
1088
1089 class Button():
6d8cfaf @djrahl set-up ai
authored
1090 """
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1091 A clickable button that is rendered on screen.
1092 """
b68496b @djrahl first commit
authored
1093 def __init__(self, text, x, y):
1094 self.text = text
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1095 startSurf = BUTTONFONT.render(self.text, True, BUTTONCLR, BUTTONTXT)
b68496b @djrahl first commit
authored
1096 self.rect = startSurf.get_rect()
1097 self.rect.center = x,y
1098
1099 def display(self):
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1100 startSurf = BUTTONFONT.render(self.text, True, BUTTONCLR, BUTTONTXT)
b68496b @djrahl first commit
authored
1101 DISPLAYSURF.blit(startSurf, self.rect)
1102
6127227 @djrahl Added more selection for Duel Mode.
authored
1103 def pressed(self, mouse):
b68496b @djrahl first commit
authored
1104 if mouse[0] > self.rect.topleft[0]:
1105 if mouse[1] > self.rect.topleft[1]:
1106 if mouse[0] < self.rect.bottomright[0]:
1107 if mouse[1] < self.rect.bottomright[1]:
1108 return True
1109 else: return False
1110 else: return False
1111 else: return False
1112 else: return False
1113
1114
6127227 @djrahl Added more selection for Duel Mode.
authored
1115 class SelectButton(Button):
1116 """
1117 Selected by color. Clicking will turn active state to True.
1118 """
1119 def __init__(self, text, x, y, a=False):
1120 Button.__init__(self, text, x, y)
1121 self.active = a
1122
1123 def display(self):
1124 if self.active == True:
353c181 @djrahl snake color changes based on consumption.
authored
1125 startSurf = BUTTONFONT.render(self.text, True, BUTTONCLR_SEL, BUTTONTXT_SEL)
6127227 @djrahl Added more selection for Duel Mode.
authored
1126 else:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1127 startSurf = BUTTONFONT.render(self.text, True, BUTTONCLR, BUTTONTXT)
6127227 @djrahl Added more selection for Duel Mode.
authored
1128
1129 DISPLAYSURF.blit(startSurf, self.rect)
1130
1131 def pressed(self, mouse):
1132 return Button.pressed(self, mouse)
1133
1134 def setActive(self, buttonlist):
1135 for button in buttonlist:
1136 if button == self:
1137 self.active = True
1138 else:
1139 button.active = False
1140
1141
b68496b @djrahl first commit
authored
1142 def main():
6d8cfaf @djrahl set-up ai
authored
1143 global FPSCLOCK, DISPLAYSURF, BASICFONT, BUTTONFONT, DEBUG
1144
1145 # for debugging
1146 if len(sys.argv) < 2:
1147 DEBUG = False
1148 else:
1149 DEBUG = True
b68496b @djrahl first commit
authored
1150
1151 pygame.init()
1152 FPSCLOCK = pygame.time.Clock()
1153 DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
1154 BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
9504e62 @djrahl added party mode.
authored
1155 BUTTONFONT = pygame.font.Font('freesansbold.ttf', 30)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1156 pygame.display.set_caption('Snakey Party')
b68496b @djrahl first commit
authored
1157
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1158 titleFont = pygame.font.Font('freesansbold.ttf', 64)
1159 titleSurf = titleFont.render('Snakey Party', True, WHITE, FORESTGREEN)
1160 titleRect = titleSurf.get_rect()
9504e62 @djrahl added party mode.
authored
1161 titleRect.center = (WINDOWWIDTH / 2, WINDOWHEIGHT * 2/8)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1162
9504e62 @djrahl added party mode.
authored
1163 arcadebutton = Button('(a)rcade mode', WINDOWWIDTH / 2, WINDOWHEIGHT * 3/8)
1164 duelbutton = Button('(d)uel mode', WINDOWWIDTH / 2, WINDOWHEIGHT * 4/8)
1165 partybutton = Button('(p)arty mode', WINDOWWIDTH / 2, WINDOWHEIGHT * 5/8)
c9dd311 @djrahl added tron(y) mode.
authored
1166 tronybutton = Button('(t)ron-y mode', WINDOWWIDTH / 2, WINDOWHEIGHT * 6/8)
1167 instructbutton = Button('(i)nstructions', WINDOWWIDTH / 2, WINDOWHEIGHT * 7/8)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1168
1169 while True: ### need to update this
1170
353c181 @djrahl snake color changes based on consumption.
authored
1171 DISPLAYSURF.fill(BACKGROUNDCLR)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1172 DISPLAYSURF.blit(titleSurf, titleRect)
1173 arcadebutton.display()
1174 duelbutton.display()
9504e62 @djrahl added party mode.
authored
1175 partybutton.display()
c9dd311 @djrahl added tron(y) mode.
authored
1176 tronybutton.display()
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1177 instructbutton.display()
1178
1179 for event in pygame.event.get():
1180 if event.type == QUIT:
1181 terminate()
1182 elif event.type == MOUSEBUTTONDOWN:
1183 mouse = pygame.mouse.get_pos()
1184 if arcadebutton.pressed(mouse):
1185 pygame.event.get()
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1186 game = GameData()
6127227 @djrahl Added more selection for Duel Mode.
authored
1187 runGame(game, [SNAKEY])
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1188 showGameOverScreen()
1189 elif duelbutton.pressed(mouse):
1190 pygame.event.get()
6127227 @djrahl Added more selection for Duel Mode.
authored
1191 players = False
1192 players = showSelectPlayersScreen()
1193 if players != False:
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1194 game = GameData(10, 10, 9, 2)
6127227 @djrahl Added more selection for Duel Mode.
authored
1195 runGame(game, players)
a734fdb @djrahl Added snake choices for duel mode.
authored
1196 showGameOverScreen()
9504e62 @djrahl added party mode.
authored
1197 elif partybutton.pressed(mouse):
1198 pygame.event.get()
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1199 game = GameData(25, 12, 0, 4)
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1200 players = getPlayers()
1201 runGame(game, players)
9504e62 @djrahl added party mode.
authored
1202 showGameOverScreen()
c9dd311 @djrahl added tron(y) mode.
authored
1203 elif tronybutton.pressed(mouse):
1204 pygame.event.get()
1205 game = GameData(25, 12, 0, 0)
1206 game.trailing = True
9850469 @djrahl changed core AI methods/algorithm.
authored
1207 runGame(game, [SNAKEY, LINUS, WIGGLES, GOOBER])
c9dd311 @djrahl added tron(y) mode.
authored
1208 showGameOverScreen()
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1209 elif instructbutton.pressed(mouse):
1210 showInstructScreen()
1211 elif event.type == KEYDOWN:
1212 if event.key == K_a:
1213 pygame.event.get()
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1214 game = GameData()
6127227 @djrahl Added more selection for Duel Mode.
authored
1215 runGame(game, [SNAKEY])
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1216 showGameOverScreen()
1217 elif event.key == K_d:
1218 pygame.event.get()
6127227 @djrahl Added more selection for Duel Mode.
authored
1219 players = False
1220 players = showSelectPlayersScreen()
1221 if players != False:
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1222 game = GameData(10, 10, 9, 2)
6127227 @djrahl Added more selection for Duel Mode.
authored
1223 runGame(game, players)
a734fdb @djrahl Added snake choices for duel mode.
authored
1224 showGameOverScreen()
9504e62 @djrahl added party mode.
authored
1225 elif event.key == K_p:
1226 pygame.event.get()
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1227 game = GameData(25, 12, 0, 4)
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1228 players = getPlayers()
1229 runGame(game, players)
9504e62 @djrahl added party mode.
authored
1230 showGameOverScreen()
c9dd311 @djrahl added tron(y) mode.
authored
1231 elif event.key == K_t:
1232 pygame.event.get()
1233 game = GameData(25, 12, 0, 0)
1234 game.trailing = True
9850469 @djrahl changed core AI methods/algorithm.
authored
1235 runGame(game, [SNAKEY, LINUS, WIGGLES, GOOBER])
c9dd311 @djrahl added tron(y) mode.
authored
1236 showGameOverScreen()
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1237 elif event.key == K_i:
1238 showInstructScreen()
1239 elif event.key == K_ESCAPE or event.key == K_q:
1240 terminate()
1241
6127227 @djrahl Added more selection for Duel Mode.
authored
1242 game = False
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1243 pygame.display.update()
1244 FPSCLOCK.tick(FPS)
9504e62 @djrahl added party mode.
authored
1245
b68496b @djrahl first commit
authored
1246
6127227 @djrahl Added more selection for Duel Mode.
authored
1247 def runGame(game, players=[]):
b68496b @djrahl first commit
authored
1248
6d8cfaf @djrahl set-up ai
authored
1249 # in game variables
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1250 allsnake = []
1251 allfruit = []
6127227 @djrahl Added more selection for Duel Mode.
authored
1252 nextEvent = 0
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1253
6127227 @djrahl Added more selection for Duel Mode.
authored
1254 # create snakes based on name. 'player' is set to false initially to handle input
1255 player = False
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1256 pos = 1
6127227 @djrahl Added more selection for Duel Mode.
authored
1257 for snake in players:
1258 if snake == SNAKEY:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1259 player = Snake(SNAKEY, getStartCoords(pos))
6127227 @djrahl Added more selection for Duel Mode.
authored
1260 allsnake.append(player)
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1261 pos = pos + 1
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1262 elif snake == LINUS:
9850469 @djrahl changed core AI methods/algorithm.
authored
1263 linus = Opponent(LINUS, getStartCoords(pos), IVORY, COBALTGREEN, 5, 20, -20)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1264 allsnake.append(linus)
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1265 pos = pos + 1
6127227 @djrahl Added more selection for Duel Mode.
authored
1266 elif snake == WIGGLES:
9850469 @djrahl changed core AI methods/algorithm.
authored
1267 wiggles = Opponent(WIGGLES, getStartCoords(pos), SLATEBLUE, WHITE, 20, 5, -5, [60, -10, 40, 10, 25, 100])
6127227 @djrahl Added more selection for Duel Mode.
authored
1268 allsnake.append(wiggles)
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1269 pos = pos + 1
9850469 @djrahl changed core AI methods/algorithm.
authored
1270 elif snake == GOOBER:
1271 goober = Opponent(GOOBER, getStartCoords(pos), PINK, RED, 10, 10, -15, [30, 5, 60, 30, 35, 100])
1272 allsnake.append(goober)
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1273 pos = pos + 1
b68496b @djrahl first commit
authored
1274
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1275 # create initial apple(s)
1276 appleCounter = game.apples
1277 while appleCounter > 0:
1278 a = Apple(allfruit, allsnake, game)
1279 allfruit.append(a)
1280 appleCounter = appleCounter - 1
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
1281
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1282 # main game loop
1283 while True:
6127227 @djrahl Added more selection for Duel Mode.
authored
1284
6d8cfaf @djrahl set-up ai
authored
1285 # get grid representation for AIs
1286 grid = getGrid(allsnake, allfruit)
1287
6127227 @djrahl Added more selection for Duel Mode.
authored
1288 # event handling loop -- get player's direction choice
1289 stop = False
1290
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1291 # get events in queue. This updates players direction and other key instructions (quit, debug...)
1292 # if the next event after direction update suggests sharp direction change, following direction is stored.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1293 for event in pygame.event.get():
b68496b @djrahl first commit
authored
1294 if event.type == QUIT:
1295 terminate()
6127227 @djrahl Added more selection for Duel Mode.
authored
1296 elif nextEvent != 0 and player != False:
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1297 player.direction = nextEvent
1298 nextEvent = 0
1299 stop = True
6127227 @djrahl Added more selection for Duel Mode.
authored
1300 # check for exit/quit/debug keys
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1301 if event.type == KEYDOWN and \
1302 (event.key == K_ESCAPE or event.key == K_q):
6127227 @djrahl Added more selection for Duel Mode.
authored
1303 terminate()
1304 elif event.type == KEYDOWN and event.key == K_e:
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1305 showGameStats(allsnake)
6127227 @djrahl Added more selection for Duel Mode.
authored
1306 return 1
1307 elif event.type == KEYDOWN and event.key == K_g and DEBUG == True:
1308 stop = True
1309 debugPrintGrid(grid)
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1310 # if player is dead / does not exist - check for speed controls
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1311 elif event.type == KEYDOWN and event.key == K_f and \
1312 (player == False or player.alive == False):
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1313 game.updateBaseSpeed(10)
1314 game.updateCurrentSpeed(False, True)
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1315 elif event.type == KEYDOWN and event.key == K_s and \
1316 (player == False or player.alive == False):
ef0acb2 @djrahl consolidated game over sequence.
authored
1317 game.updateBaseSpeed(-10)
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1318 game.updateCurrentSpeed(False, True)
6127227 @djrahl Added more selection for Duel Mode.
authored
1319
1320 # if player exists - check for direction input
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1321 if event.type == KEYDOWN and \
1322 player != False and stop == False:
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1323 if event.key == K_LEFT and player.direction != RIGHT:
6d8cfaf @djrahl set-up ai
authored
1324 player.direction = LEFT
b68496b @djrahl first commit
authored
1325 stop = True
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1326 elif event.key == K_RIGHT and player.direction != LEFT:
6d8cfaf @djrahl set-up ai
authored
1327 player.direction = RIGHT
b68496b @djrahl first commit
authored
1328 stop = True
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1329 elif event.key == K_UP and player.direction != DOWN:
6d8cfaf @djrahl set-up ai
authored
1330 player.direction = UP
b68496b @djrahl first commit
authored
1331 stop = True
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1332 elif event.key == K_DOWN and player.direction != UP:
6d8cfaf @djrahl set-up ai
authored
1333 player.direction = DOWN
6127227 @djrahl Added more selection for Duel Mode.
authored
1334
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1335 # peak into very next event. If key suggests sharp direction change, store in nextEvent
6127227 @djrahl Added more selection for Duel Mode.
authored
1336 elif event.type == KEYDOWN and player != False and nextEvent == 0:
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1337 if event.key == K_LEFT and player.direction != RIGHT:
1338 nextEvent = LEFT
1339 elif event.key == K_RIGHT and player.direction != LEFT:
1340 nextEvent = RIGHT
1341 elif event.key == K_UP and player.direction != DOWN:
1342 nextEvent = UP
1343 elif event.key == K_DOWN and player.direction != UP:
1344 nextEvent = DOWN
1345 elif event.key == K_ESCAPE or event.key == K_q:
1346 terminate()
1347 elif event.key == K_g and DEBUG == True:
1348 debugPrintGrid(grid)
6d8cfaf @djrahl set-up ai
authored
1349
1350 if DEBUG == True:
1351 debugPause()
1352
1353 # update all other snake's direction choice
1354 for snake in allsnake:
1355 if snake.alive and snake.player == False:
1356 snake.updateDirection(grid)
b68496b @djrahl first commit
authored
1357
6d8cfaf @djrahl set-up ai
authored
1358 # collision detection
b68496b @djrahl first commit
authored
1359 for snake in allsnake:
6d8cfaf @djrahl set-up ai
authored
1360 # check if the snake has hit boundary
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1361 if snake.alive and snake.boundsCollision():
b68496b @djrahl first commit
authored
1362 snake.alive = False
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1363 # check if snake has hit another snake
1364 for othersnake in allsnake:
1365 if snake.alive and snake.snakeCollision(othersnake):
b68496b @djrahl first commit
authored
1366 snake.alive = False
1367
1368 # check if fruit has been eaten by a snake
1369 for snake in allsnake:
1370 for fruit in allfruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1371 if snake.alive and snake.fruitCollision(fruit):
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1372 fruit.isEaten(snake, game)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1373 # apples have special adding properties
1374 if fruit.__class__ == Apple:
b68496b @djrahl first commit
authored
1375 # check for speed increase
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1376 if game.checkSpeedTrigger():
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1377 game.updateBaseSpeed(1)
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1378 # check for fruit bonus drop
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1379 if game.checkBonusTrigger():
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1380 game.runBonusFruit(allfruit, allsnake)
1381 # run usual fruid drop
1382 game.runDrop(allfruit, allsnake)
1383 # blueberries have special speed adjusting properties
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1384 elif fruit.__class__ == Blueberry:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1385 # update game frames to be 'slow' by 7 seconds
1386 game.slowtimer = game.slowtimer + game.currentspeed * 7
b68496b @djrahl first commit
authored
1387 # remove fruit
1388 allfruit.remove(fruit)
1389
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1390 # check for snake death, update place and end game if no more snakes are alive
1391 if game.checkSnakeDeath(allsnake):
6127227 @djrahl Added more selection for Duel Mode.
authored
1392 showGameStats(allsnake)
1393 return 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1394
1395 # check for size changes / move snake
1396 for snake in allsnake:
c9dd311 @djrahl added tron(y) mode.
authored
1397 snake.move(game.trailing)
b68496b @djrahl first commit
authored
1398
1399 # check multiplier and adjust color and multiplier as needed
1400 for snake in allsnake:
1401 if snake.multipliertimer > 0:
1402 snake.multipliertimer = snake.multipliertimer - 1
353c181 @djrahl snake color changes based on consumption.
authored
1403 snake.setColorBorderCurrent(PURPLE)
b68496b @djrahl first commit
authored
1404 else:
4ae7881 @djrahl Fixed grid and snake color changes.
authored
1405 # make sure multiplier is 1, color is normal
b68496b @djrahl first commit
authored
1406 snake.multiplier = 1
353c181 @djrahl snake color changes based on consumption.
authored
1407 snake.resetColorBorder()
b68496b @djrahl first commit
authored
1408
1409 # check slow and adjust color and fps as needed
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1410 if game.checkSlowTimer():
1411 game.updateSlowTimer()
1412 game.updateCurrentSpeed(FREEZING_POINT)
b68496b @djrahl first commit
authored
1413 for snake in allsnake:
353c181 @djrahl snake color changes based on consumption.
authored
1414 snake.setColorCurrent(BLUE)
b68496b @djrahl first commit
authored
1415 else:
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1416 game.updateCurrentSpeed()
4ae7881 @djrahl Fixed grid and snake color changes.
authored
1417 # make sure color is normal
1418 for snake in allsnake:
353c181 @djrahl snake color changes based on consumption.
authored
1419 snake.resetColor()
b68496b @djrahl first commit
authored
1420
1421 # update timers on fruits, remove if necessary
1422 for fruit in allfruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1423 if fruit.__class__ != Apple:
1424 if fruit.updateTimer() == False:
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1425 # if timer on Egg expires, hatch new snake
1426 if fruit.__class__ == Egg:
1427 fruit.isHatched(allsnake)
b68496b @djrahl first commit
authored
1428 allfruit.remove(fruit)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1429
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1430 # draw everything to screen
353c181 @djrahl snake color changes based on consumption.
authored
1431 DISPLAYSURF.fill(BACKGROUNDCLR)
b68496b @djrahl first commit
authored
1432 drawGrid()
1433 for fruit in allfruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1434 fruit.drawFruit()
b68496b @djrahl first commit
authored
1435 for snake in allsnake:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1436 snake.drawSnake()
6d8cfaf @djrahl set-up ai
authored
1437
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1438 # print scores only if snake is scored
6d8cfaf @djrahl set-up ai
authored
1439 position = 1
1440 for snake in allsnake:
daf5948 @djrahl added Egg (inherited from Fruit Class)-- adds snakes if not eaten.
authored
1441 if snake.scored == True:
1442 snake.drawScore(position, allsnake)
1443 position = position + 1
b1cc6ae @djrahl moved bonuses and drops to Gamedata class. Party mode generates rando…
authored
1444
573b079 @djrahl moved fps changes to game class; added speed controls when only AIs p…
authored
1445 # if player is dead, print extra messages
1446 if player == False or player.alive == False:
d313d65 @djrahl fixed places in gamestats; end game requires only one click/key to re…
authored
1447 endMessage = 'press (e) to end game early'
1448 fastMessage = 'press (f) to fast-forward game'
1449 slowMessage = 'press (s) to slow game'
1450 drawMessage(endMessage, WINDOWWIDTH / 2, WINDOWHEIGHT / 20 * 16)
1451 drawMessage(fastMessage, WINDOWWIDTH / 2, WINDOWHEIGHT / 20 * 17)
1452 drawMessage(slowMessage, WINDOWWIDTH / 2, WINDOWHEIGHT / 20 * 18)
b68496b @djrahl first commit
authored
1453 pygame.display.update()
c46945d @djrahl Moved Tally Class into Game Data- now passed from menu. Added support…
authored
1454 FPSCLOCK.tick(game.currentspeed)
b68496b @djrahl first commit
authored
1455
1456
1457 def checkForKeyPress():
1458 if len(pygame.event.get(QUIT)) > 0:
1459 terminate()
1460
1461 keyUpEvents = pygame.event.get(KEYUP)
1462 if len(keyUpEvents) == 0:
1463 return None
1464