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