Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 1201 lines (1030 sloc) 44.849 kB
b68496b @djrahl first commit
authored
1 #!/usr/bin/env python
2 # a snakey clone using pygame
3
4 import random, pygame, sys
5 from pygame.locals import *
6
7 WINDOWWIDTH = 640
8 WINDOWHEIGHT = 480
6c613da @djrahl Worked on AI; added crude apple detection.
authored
9 FPS = 12
b68496b @djrahl first commit
authored
10 CELLSIZE = 20
6c613da @djrahl Worked on AI; added crude apple detection.
authored
11 BUFFER = CELLSIZE * 1 # number of cells to exclude from grid height; displays in-game info
b68496b @djrahl first commit
authored
12 assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
6d8cfaf @djrahl set-up ai
authored
13 assert (WINDOWHEIGHT - BUFFER) % CELLSIZE == 0, "Window height must be a multiple of cell size."
b68496b @djrahl first commit
authored
14 CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
6d8cfaf @djrahl set-up ai
authored
15 CELLHEIGHT = int((WINDOWHEIGHT - BUFFER) / CELLSIZE)
b68496b @djrahl first commit
authored
16
6c613da @djrahl Worked on AI; added crude apple detection.
authored
17 # colors
b68496b @djrahl first commit
authored
18 WHITE = (255, 255, 255)
19 BLACK = (0, 0, 0)
20 RED = (255, 0, 0)
21 GREEN = (0, 255, 0)
22 BLUE = (0, 0, 255)
23 DARKGRAY = (40, 40, 40)
24 HONEYDEW = (240, 255, 240)
25 MINTGREEN = (189, 252, 201)
26 SEAGREEN = (84, 255, 159)
27 EMERALDGREEN = (0, 201, 87)
28 FORESTGREEN = (34, 139, 34)
29 COBALTGREEN = (61, 145, 64)
30 GREENYELLOW = (173, 255, 47)
31 OLIVEGREEN = (107, 142, 35)
32 IVORY = (205, 205, 193)
33 LIGHTYELLOW = (238, 238, 209)
34 YELLOW = (238, 238, 0)
35 KHAKI = (255, 246, 143)
36 GOLDENROD = (218, 165, 32)
37 CORAL = (255, 127, 80)
38 SIENNA = (255, 130, 71)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
39 ORANGE = (255, 127, 0)
b68496b @djrahl first commit
authored
40 PURPLE = (142, 56, 142)
41 MAROON = (255, 52, 179)
42 BGCOLOR = BLACK
43
6c613da @djrahl Worked on AI; added crude apple detection.
authored
44 # for consistency in direction types
b68496b @djrahl first commit
authored
45 UP = 'up'
46 DOWN = 'down'
47 LEFT = 'left'
48 RIGHT = 'right'
49
6c613da @djrahl Worked on AI; added crude apple detection.
authored
50 # for consistency in snake names
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
51 WIGGLES = 'wiggles'
52 GIGGLES = 'giggles'
53 LINUS = 'linus'
54
6c613da @djrahl Worked on AI; added crude apple detection.
authored
55 # index of snake's head
56 HEAD = 0
b68496b @djrahl first commit
authored
57
6c613da @djrahl Worked on AI; added crude apple detection.
authored
58 # minimum and maximum frames fruit remains on screen
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
59 POISONTIMER = (100,200)
60 ORANGETIMER = (35,65)
61 RASPBERRYTIMER = (30,45)
62 BLUEBERRYTIMER = (20,40)
63 LEMONTIMER = (100,100)
64
65 POISONBONUS = 7
66 ORANGEBONUS = 8
67 RASPBERRYBONUS = 9
68 BLUEBERRYBONUS = 10
69 LEMONBONUS = 11
b68496b @djrahl first commit
authored
70
71
72 class Snake:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
73 """
74 Snake class houses all information for a particular snake.
75 player - if snake is the player. Player snake is also referenced directly when player snake object is created.
6d8cfaf @djrahl set-up ai
authored
76 name - name of snake.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
77 alive - if snake is alive. Rather than delete, this allows snake to slowly shrink to the point of where it died.
78 coords - a list of dictionaries containing coordinates 'x' and 'y'. A special global variable HEAD (0).
79 direction - where snake moves for every game iteration ('left', 'up', etc).
80 color - body of snake's color.
81 colorBorder - outline of body.
82 growth - when a snake is to grow, this is stored in this buffer so that every game iteration can add one growth, only.
83 multiplier - all fruit eaten which cause points to be scored are multiplied by this.
84 multipliertimer - number of game iterations multiplier stays in effect.
85 score - the number of points snake has accumulated.
86 """
6d8cfaf @djrahl set-up ai
authored
87 def __init__(self, n='snakey', c=[{'x':5, 'y':5},{'x':4, 'y':5},{'x':3, 'y':5}], d=RIGHT, sc=GREEN, sb=COBALTGREEN):
b68496b @djrahl first commit
authored
88 self.player = False
6d8cfaf @djrahl set-up ai
authored
89 self.name = n
b68496b @djrahl first commit
authored
90 self.alive = True
91 self.coords = c
92 # ensure snake length
93 assert len(self.coords) > 1
94 self.direction = d
95 self.color = sc
4ae7881 @djrahl Fixed grid and snake color changes.
authored
96 self.colorCurrent = self.color
b68496b @djrahl first commit
authored
97 self.colorBorder = sb
4ae7881 @djrahl Fixed grid and snake color changes.
authored
98 self.colorBorderCurrent = self.colorBorder
b68496b @djrahl first commit
authored
99 self.growth = 0
100 self.multiplier = 1
101 self.multipliertimer = 0
102 self.score = 0
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
103 self.fruitEaten = {'apple':0, 'poison':0, 'orange':0, 'raspberry':0, 'blueberry':0, 'lemon':0}
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
104
105 def updateScore(self, points_input):
106 """
107 This updates score of snake, factoring multiplier.
108 """
109 self.score = self.score + (points_input * self.multiplier)
110
111 def updateGrowth(self, growth_input):
112 """
113 This updates growth "owed" to snake, allowing amount to stack.
114 """
115 self.growth = self.growth + growth_input
116
117 def updateMultiplier(self, multiplier_input, timer_input):
118 """
119 This updates multiplier value and time (game iterations) multiplier is active. Only time stacks.
120 """
121 # multiplier value does not stack, but time does
122 self.multiplier = multiplier_input
123 self.multipliertimer = self.multipliertimer + timer_input
124
125 def boundsCollision(self):
126 """
127 This returns True if snake (head) is ever out of grid parameters.
128 """
6d8cfaf @djrahl set-up ai
authored
129 # check if out of bounds -- offset on on 'y' for buffer.
130 if self.coords[HEAD]['x'] == -1 or self.coords[HEAD]['x'] == CELLWIDTH or self.coords[HEAD]['y'] == -1 + (BUFFER / CELLSIZE) or self.coords[HEAD]['y'] == CELLHEIGHT + (BUFFER / CELLSIZE):
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
131 return True
132 else:
133 return False
134
135 def snakeCollision(self, snake):
136 """
137 This returns True if snake (head) collides with any part of a given snake (outside of own head if checking against self).
138 """
139 if self is snake:
140 # exclude head if checked against self
141 for snakebody in snake.coords[1:]:
142 if snakebody['x'] == self.coords[HEAD]['x'] and snakebody['y'] == self.coords[HEAD]['y']:
143 return True
144 else:
145 for snakebody in snake.coords:
146 if snakebody['x'] == self.coords[HEAD]['x'] and snakebody['y'] == self.coords[HEAD]['y']:
147 return True
148 # no collision
149 return False
150
151 def fruitCollision(self, fruit):
152 """
153 This returns True if snake (head) has collided with a given fruit.
154 """
155 if self.coords[HEAD]['x'] == fruit.coords['x'] and self.coords[HEAD]['y'] == fruit.coords['y']:
156 return True
157 else:
158 return False
159
160 def move(self):
161 """
162 This will update coords for snake, moving it one cell in given direction.
163 It also factors in and updates growth if any growth is "owed" snake (one per game iteration).
164 If snake is dead, will only remove the last segment of snake and ignore direction / not move snake.
165 """
166 if self.alive:
167 # delete last segment first.
168 if self.growth < 0:
169 self.growth = self.growth + 1
170 if len(self.coords) > 3:
171 # implement negative growth by removing last two segments
172 del self.coords[-2:]
173 else:
174 # snake is too short -- remove last segment as normal
175 del self.coords[-1]
176 elif self.growth > 0:
177 self.growth = self.growth - 1
178 # implement positive growth by not deleting last segment
179 else:
180 # no growth factor, delete last segment
181 del self.coords[-1]
182
183 # determine new head coordinates by direction
184 if self.direction == UP:
185 newhead = {'x': self.coords[HEAD]['x'], 'y': self.coords[HEAD]['y'] - 1}
186 elif self.direction == DOWN:
187 newhead = {'x': self.coords[HEAD]['x'], 'y': self.coords[HEAD]['y'] + 1}
188 elif self.direction == LEFT:
189 newhead = {'x': self.coords[HEAD]['x'] - 1, 'y': self.coords[HEAD]['y']}
190 elif self.direction == RIGHT:
191 newhead = {'x': self.coords[HEAD]['x'] + 1, 'y': self.coords[HEAD]['y']}
192
193 # insert new head segment
194 self.coords.insert(HEAD, newhead)
195
196 # dead snake -- remove last segment as long as it isn't the last
197 elif len(self.coords) > 1:
198 del self.coords[-1]
199
200 def drawSnake(self):
201 """
202 Responsible for drawing snake image to screen.
203 """
204 for coord in self.coords:
205 x = coord['x'] * CELLSIZE
206 y = coord['y'] * CELLSIZE
207 snakeSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
4ae7881 @djrahl Fixed grid and snake color changes.
authored
208 pygame.draw.rect(DISPLAYSURF, self.colorBorderCurrent, snakeSegmentRect)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
209 snakeInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
4ae7881 @djrahl Fixed grid and snake color changes.
authored
210 pygame.draw.rect(DISPLAYSURF, self.colorCurrent, snakeInnerSegmentRect)
6d8cfaf @djrahl set-up ai
authored
211
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
212 def drawScore(self, position, allsnake):
6d8cfaf @djrahl set-up ai
authored
213 """
214 Responsible for drawing snake score to screen.
215 """
4ae7881 @djrahl Fixed grid and snake color changes.
authored
216 scoreSurf = BASICFONT.render('%s: %s' % (self.name, self.score), True, self.colorCurrent)
6d8cfaf @djrahl set-up ai
authored
217 scoreRect = scoreSurf.get_rect()
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
218 scoreRect.topleft = (getPosition(position, allsnake), 1)
6d8cfaf @djrahl set-up ai
authored
219 DISPLAYSURF.blit(scoreSurf, scoreRect)
220
221
222 class Opponent(Snake):
223 """
224 Derived from Snake class, this adds functionality for determining direction.
225 """
226 def __init__(self, n='bot', c=[{'x':13, 'y':10},{'x':14, 'y':10},{'x':15, 'y':10}], d=LEFT, sc=COBALTGREEN, sb=GOLDENROD, r=20, p=10):
227 Snake.__init__(self, n, c, d, sc, sb)
228 self.avoidBoundaries = True
c134769 @djrahl fixed key input bug
authored
229 self.randomness = r
6d8cfaf @djrahl set-up ai
authored
230 self.preferSameDirection = p
231
232 def updateDirection(self, grid):
233 # all directions have value adjusted
6c613da @djrahl Worked on AI; added crude apple detection.
authored
234 nextDirection = {LEFT:0, RIGHT:0, UP:0, DOWN:0}
6d8cfaf @djrahl set-up ai
authored
235
236 # coords of own snake head
237 x = self.coords[HEAD]['x']
238 y = self.coords[HEAD]['y']
239
240 # opposite direction kills snake
241 if self.direction == LEFT:
6c613da @djrahl Worked on AI; added crude apple detection.
authored
242 nextDirection[RIGHT] = nextDirection[RIGHT] - 100
6d8cfaf @djrahl set-up ai
authored
243 elif self.direction == RIGHT:
6c613da @djrahl Worked on AI; added crude apple detection.
authored
244 nextDirection[LEFT] = nextDirection[LEFT] - 100
6d8cfaf @djrahl set-up ai
authored
245 elif self.direction == UP:
6c613da @djrahl Worked on AI; added crude apple detection.
authored
246 nextDirection[DOWN] = nextDirection[DOWN] - 100
6d8cfaf @djrahl set-up ai
authored
247 elif self.direction == DOWN:
6c613da @djrahl Worked on AI; added crude apple detection.
authored
248 nextDirection[UP] = nextDirection[UP]- 100
6d8cfaf @djrahl set-up ai
authored
249
250 # avoid boundaries
251 if self.avoidBoundaries == True:
252 if x == 0:
6c613da @djrahl Worked on AI; added crude apple detection.
authored
253 nextDirection[LEFT] = nextDirection[LEFT] - 100
6d8cfaf @djrahl set-up ai
authored
254 if x == CELLWIDTH - 1:
6c613da @djrahl Worked on AI; added crude apple detection.
authored
255 nextDirection[RIGHT] = nextDirection[RIGHT] - 100
6d8cfaf @djrahl set-up ai
authored
256 if y == (BUFFER / CELLSIZE):
6c613da @djrahl Worked on AI; added crude apple detection.
authored
257 nextDirection[UP] = nextDirection[UP] - 100
6d8cfaf @djrahl set-up ai
authored
258 if y == CELLHEIGHT + (BUFFER / CELLSIZE) - 1:
6c613da @djrahl Worked on AI; added crude apple detection.
authored
259 nextDirection[DOWN] = nextDirection[DOWN] - 100
6d8cfaf @djrahl set-up ai
authored
260
261 # prefer same direction
6c613da @djrahl Worked on AI; added crude apple detection.
authored
262 nextDirection[self.direction] = nextDirection[self.direction] + self.preferSameDirection
6d8cfaf @djrahl set-up ai
authored
263
264 # avoid immediate snakes
265 if grid.has_key((x-1,y)) and (grid[(x-1,y)] == 'snake'):
6c613da @djrahl Worked on AI; added crude apple detection.
authored
266 nextDirection[LEFT] = nextDirection[LEFT] - 100
6d8cfaf @djrahl set-up ai
authored
267 if grid.has_key((x+1,y)) and (grid[(x+1,y)] == 'snake'):
6c613da @djrahl Worked on AI; added crude apple detection.
authored
268 nextDirection[RIGHT] = nextDirection[RIGHT] - 100
6d8cfaf @djrahl set-up ai
authored
269 if grid.has_key((x,y-1)) and (grid[(x,y-1)] == 'snake'):
6c613da @djrahl Worked on AI; added crude apple detection.
authored
270 nextDirection[UP] = nextDirection[UP] - 100
271 if grid.has_key((x,y+1)) and (grid[(x,y+1)] == 'snake'):
272 nextDirection[DOWN] = nextDirection[DOWN] - 100
273
274 # favor direction of apple -- this approach will need to be replaced eventually
275 for cell in grid:
276 if grid[cell] == 'apple':
277 # get x and y differences and favor direction of apple inversely proportionate to distance
278 x_difference = cell[0] - x
279 y_difference = cell[1] - y
280 if x_difference > 0:
281 nextDirection[RIGHT] = nextDirection[RIGHT] + (CELLWIDTH - x_difference)
282 else:
283 nextDirection[LEFT] = nextDirection[LEFT] + (CELLWIDTH - x_difference)
284 if y_difference < 0:
285 nextDirection[UP] = nextDirection[UP] + (CELLHEIGHT - y_difference)
286 else:
287 nextDirection[DOWN] = nextDirection[DOWN] + (CELLHEIGHT - y_difference)
6d8cfaf @djrahl set-up ai
authored
288
289 # factor in randomness
6c613da @djrahl Worked on AI; added crude apple detection.
authored
290 for d in nextDirection:
291 nextDirection[d] = nextDirection[d] + random.randint(0,self.randomness)
6d8cfaf @djrahl set-up ai
authored
292
293 # report if debugging
294 if DEBUG == True:
295 print self.name
6c613da @djrahl Worked on AI; added crude apple detection.
authored
296 print nextDirection
6d8cfaf @djrahl set-up ai
authored
297
298 # update snake direction to direction with highest score
6c613da @djrahl Worked on AI; added crude apple detection.
authored
299 self.direction = max(nextDirection, key=nextDirection.get)
6d8cfaf @djrahl set-up ai
authored
300
301 def updateScore(self, points_input):
302 Snake.updateScore(self, points_input)
303
304 def updateGrowth(self, growth_input):
305 Snake.updateGrowth(self, growth_input)
306
307 def updateMultiplier(self, multiplier_input, timer_input):
308 Snake.updateMultiplier(self, multiplier_input, timer_input)
309
310 def boundsCollision(self):
311 return Snake.boundsCollision(self)
312
313 def snakeCollision(self, snake):
314 return Snake.snakeCollision(self, snake)
315
316 def fruitCollision(self, fruit):
317 return Snake.fruitCollision(self, fruit)
318
319 def move(self):
320 Snake.move(self)
321
322 def drawSnake(self):
323 Snake.drawSnake(self)
324
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
325 def drawScore(self, position, allsnake):
326 Snake.drawScore(self, position, allsnake)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
327
b68496b @djrahl first commit
authored
328
329 class Fruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
330 """
331 Fruit class houses all information for fruit objects. Base class is not meant to be instantiated, but rather provide base methods shared by all fruit.
332 """
333 def __init__(self):
334 self.timer = 0
335
336 def getRandomLocation(self, allfruit, allsnake, gametally):
337 """
338 Returns random coordinates (for fruit to be placed). Ensures that coordinates are not occupied by fruit or snake head.
339 Will keep fruit away from edges (outside 20%) if in an "easy mode" determined in Tally object.
340 """
b68496b @djrahl first commit
authored
341 while True:
342 conflict = False
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
343 if gametally.checkEasyTrigger():
b68496b @djrahl first commit
authored
344 x = random.randint(int(CELLWIDTH/5), CELLWIDTH - int(CELLWIDTH/5) - 1)
345 y = random.randint(int(CELLHEIGHT/5), CELLHEIGHT - int(CELLHEIGHT/5) - 1)
346 else:
347 x = random.randint(0, CELLWIDTH - 1)
6d8cfaf @djrahl set-up ai
authored
348 y = random.randint((BUFFER / CELLSIZE), CELLHEIGHT - 1)
b68496b @djrahl first commit
authored
349 # ensure coordinates are not already occupied by fruit
350 for fruit in allfruit:
351 if fruit.coords['x'] == x and fruit.coords['y'] == y:
352 conflict = True
353 # ensure coordinates are not already occupied by snake head
354 for snake in allsnake:
355 if snake.coords[HEAD]['x'] == x and snake.coords[HEAD]['y'] == y:
356 conflict = True
357 if conflict == False:
358 return {'x':x, 'y':y}
359
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
360 def updateTimer(self):
361 """
362 Returns true and decrements if there is still time left for fruit to be on screen.
363 """
b68496b @djrahl first commit
authored
364 if self.timer > 0:
365 self.timer = self.timer - 1
366 return True
367 else:
368 return False
369
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
370 def drawFruit(self):
371 """
372 Responsible for drawing fruit image to screen.
373 """
374 x = self.coords['x'] * CELLSIZE
375 y = self.coords['y'] * CELLSIZE
376 fruitRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
377 pygame.draw.rect(DISPLAYSURF, self.color, fruitRect)
378
379
380 class Apple(Fruit):
381 """
382 Apples are a unique fruit in that they never leave the screen and once one is eaten, it is always replaced with another.
383 They also add points and one growth
384 """
385 def __init__(self, allfruit, allsnake, gametally):
386 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, gametally)
387 self.color = RED
388 self.points = 10
389 self.growth = 1
390
391 def isEaten(self, snake, gametally):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
392 snake.fruitEaten['apple'] = snake.fruitEaten['apple'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
393 gametally.fruitEaten['apple'] = gametally.fruitEaten['apple'] + 1
394 snake.updateScore(self.points)
395 snake.updateGrowth(self.growth)
396
397 def drawFruit(self):
398 Fruit.drawFruit(self)
399
400
401 class Poison(Fruit):
402 """
403 Poison will shorten a snake (by adding a negative growth value) and reduce points.
404 """
405 def __init__(self, allfruit, allsnake, gametally):
406 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, gametally)
407 self.timer = random.randint(POISONTIMER[0], POISONTIMER[1])
408 self.color = GREEN
409 self.points = -25
410 self.growth = -3
411
412 def isEaten(self, snake, gametally):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
413 snake.fruitEaten['poison'] = snake.fruitEaten['poison'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
414 gametally.fruitEaten['poison'] = gametally.fruitEaten['poison'] + 1
415 snake.updateScore(self.points)
416 snake.updateGrowth(self.growth)
417
418 def updateTimer(self):
419 return Fruit.updateTimer(self)
420
421 def drawFruit(self):
422 Fruit.drawFruit(self)
423
424
425 class Orange(Fruit):
426 """
427 Orange will grow snake substantially and are worth points.
428 """
429 def __init__(self, allfruit, allsnake, gametally):
430 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, gametally)
431 self.timer = random.randint(ORANGETIMER[0], ORANGETIMER[1])
432 self.color = ORANGE
433 self.points = 50
434 self.growth = 3
435
436 def isEaten(self, snake, gametally):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
437 snake.fruitEaten['orange'] = snake.fruitEaten['orange'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
438 gametally.fruitEaten['orange'] = gametally.fruitEaten['orange'] + 1
439 snake.updateScore(self.points)
440 snake.updateGrowth(self.growth)
441
442 def updateTimer(self):
443 return Fruit.updateTimer(self)
444
445 def drawFruit(self):
446 Fruit.drawFruit(self)
447
448
449 class Raspberry(Fruit):
450 """
451 Raspberry will set snake's multiplier to two for a period of time.
452 """
453 def __init__(self, allfruit, allsnake, gametally):
454 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, gametally)
455 self.timer = random.randint(RASPBERRYTIMER[0], RASPBERRYTIMER[1])
456 self.color = PURPLE
457 self.multiplier = 2
458 self.multipliertimer = 100
459
460 def isEaten(self, snake, gametally):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
461 snake.fruitEaten['raspberry'] = snake.fruitEaten['raspberry'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
462 gametally.fruitEaten['raspberry'] = gametally.fruitEaten['raspberry'] + 1
463 snake.updateMultiplier(self.multiplier, self.multipliertimer)
464
465 def updateTimer(self):
466 return Fruit.updateTimer(self)
467
468 def drawFruit(self):
469 Fruit.drawFruit(self)
470
471
472 class Blueberry(Fruit):
473 """
474 Blueberry will reduce the frame rate (slowing down game iterations) for a period of time.
475 It is also worth a lot of points.
476 """
477 def __init__(self, allfruit, allsnake, gametally):
478 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, gametally)
479 self.timer = random.randint(BLUEBERRYTIMER[0], BLUEBERRYTIMER[1])
480 self.color = BLUE
481 self.score = 100
a734fdb @djrahl Added snake choices for duel mode.
authored
482 self.slowtimer = 80
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
483
484 def isEaten(self, snake, gametally):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
485 snake.fruitEaten['blueberry'] = snake.fruitEaten['blueberry'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
486 gametally.fruitEaten['blueberry'] = gametally.fruitEaten['blueberry'] + 1
487 snake.updateScore(self.score)
488
489 def updateTimer(self):
490 return Fruit.updateTimer(self)
491
492 def drawFruit(self):
493 Fruit.drawFruit(self)
494
495
496 class Lemon(Fruit):
ff23b3c @djrahl Worked on AI.
authored
497 """
4ae7881 @djrahl Fixed grid and snake color changes.
authored
498 TBD... currently worth 1000 points.
499 """
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
500 def __init__(self, allfruit, allsnake, gametally):
501 self.coords = Fruit.getRandomLocation(self, allfruit, allsnake, gametally)
502 self.timer = random.randint(LEMONTIMER[0], LEMONTIMER[1])
503 self.color = YELLOW
504 self.score = 1000
505
506 def isEaten(self, snake, gametally):
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
507 snake.fruitEaten['lemon'] = snake.fruitEaten['lemon'] + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
508 gametally.fruitEaten['lemon'] = gametally.fruitEaten['lemon'] + 1
509 snake.updateScore(self.score)
510
511 def updateTimer(self):
512 return Fruit.updateTimer(self)
513
514 def drawFruit(self):
515 Fruit.drawFruit(self)
516
517
518 class Tally:
519 """
520 Responsible for dynamics relating to the accumulation of fruits in a given game.
521 fruitEaten - a dictionary containing a numeric tally of each fruit eaten.
522 speedTrigger - the frequency (based on apples consumed) in which gamespeed is increased by one.
523 bonusTrigger - the frequency (based on apples consumed) in which a bonus game - runBonus() - is launched.
524 easyTrigger - a threshold (apples consumed); once reached fruit can be placed anywhere on screen (as opposed to away from edges).
525 typeMin - the minimum value in determining bonus game type.
526 typeMax - the maximum value in determining bonus game type.
527 """
528 def __init__(self, st=20, bt=10, et=20, tmin=1, tmax=10):
529 self.fruitEaten = {'apple':0, 'poison':0, 'orange':0, 'raspberry':0, 'blueberry':0, 'lemon':0}
530 self.speedTrigger = st
531 self.bonusTrigger = bt
532 self.easyTrigger = et
533 self.typeMin = tmin
534 self.typeMax = tmax
535
536 def checkSpeedTrigger(self):
537 """
538 Returns true if number of apples consumed modulo speedTrigger equals zero.
539 """
540 if self.fruitEaten['apple'] % self.speedTrigger == 0:
541 return True
542 else:
543 return False
544
545 def checkBonusTrigger(self):
546 """
547 Returns true if number of apples consumed modulo bonusTrigger equals zero.
548 """
549 if self.fruitEaten['apple'] % self.bonusTrigger == 0:
550 return True
551 else:
552 return False
553
554 def checkEasyTrigger(self):
555 """
556 Returns true if number of apples consumed is less than or equal to easyTrigger.
557 """
558 if self.fruitEaten['apple'] <= self.easyTrigger:
559 return True
560 else:
561 return False
562
563 def runBonus(self):
564 """
565 Returns a list containing fruit (as strings) to be added to game from bonus game.
566 An integer (determined randomly between typeMin and typeMax) corresponds to bonus game run.
567 A basic set-up would randomly choose between 1 and 10; 6 through 10 initiating a fruit specific bonus.
568 Default will contain an assortment of fruit.
569 """
570 bonus = []
571 type = random.randint(self.typeMin, self.typeMax)
572 if type == LEMONBONUS:
573 bonus.append('lemon')
574 elif type == POISONBONUS:
575 counter = random.randint(20,35)
576 while counter > 0:
577 bonus.append('poison')
578 counter = counter - 1
579 elif type == ORANGEBONUS:
580 counter = random.randint(20,35)
581 while counter > 0:
582 bonus.append('orange')
583 counter = counter - 1
584 elif type == RASPBERRYBONUS:
585 counter = random.randint(20,35)
586 while counter > 0:
587 bonus.append('raspberry')
588 counter = counter - 1
589 elif type == BLUEBERRYBONUS:
590 counter = random.randint(20,30)
591 while counter > 0:
592 bonus.append('blueberry')
593 counter = counter - 1
594 else: # default bonus
595 counter = random.randint(0,3)
596 while counter > 0:
597 bonus.append('poison')
598 counter = counter - 1
599 counter = random.randint(5,20)
600 while counter > 0:
601 bonus.append('orange')
602 counter = counter - 1
603 counter = random.randint(1,4)
604 while counter > 0:
605 bonus.append('raspberry')
606 counter = counter - 1
607 counter = random.randint(0,2)
608 while counter > 0:
609 bonus.append('blueberry')
610 counter = counter - 1
611 return bonus
612
b68496b @djrahl first commit
authored
613
614 class Button():
6d8cfaf @djrahl set-up ai
authored
615 """
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
616 A clickable button that is rendered on screen.
617 """
b68496b @djrahl first commit
authored
618 def __init__(self, text, x, y):
619 self.text = text
620 startSurf = BUTTONFONT.render(self.text, True, GREEN, DARKGRAY)
621 self.rect = startSurf.get_rect()
622 self.rect.center = x,y
623
624 def display(self):
625 startSurf = BUTTONFONT.render(self.text, True, GREEN, DARKGRAY)
626 DISPLAYSURF.blit(startSurf, self.rect)
627
628 def pressed(self,mouse):
629 if mouse[0] > self.rect.topleft[0]:
630 if mouse[1] > self.rect.topleft[1]:
631 if mouse[0] < self.rect.bottomright[0]:
632 if mouse[1] < self.rect.bottomright[1]:
633 return True
634 else: return False
635 else: return False
636 else: return False
637 else: return False
638
639
640 def main():
6d8cfaf @djrahl set-up ai
authored
641 global FPSCLOCK, DISPLAYSURF, BASICFONT, BUTTONFONT, DEBUG
642
643 # for debugging
644 if len(sys.argv) < 2:
645 DEBUG = False
646 else:
647 DEBUG = True
b68496b @djrahl first commit
authored
648
649 pygame.init()
650 FPSCLOCK = pygame.time.Clock()
651 DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
652 BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
9504e62 @djrahl added party mode.
authored
653 BUTTONFONT = pygame.font.Font('freesansbold.ttf', 30)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
654 pygame.display.set_caption('Snakey Party')
b68496b @djrahl first commit
authored
655
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
656 titleFont = pygame.font.Font('freesansbold.ttf', 64)
657 titleSurf = titleFont.render('Snakey Party', True, WHITE, FORESTGREEN)
658 titleRect = titleSurf.get_rect()
9504e62 @djrahl added party mode.
authored
659 titleRect.center = (WINDOWWIDTH / 2, WINDOWHEIGHT * 2/8)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
660
9504e62 @djrahl added party mode.
authored
661 arcadebutton = Button('(a)rcade mode', WINDOWWIDTH / 2, WINDOWHEIGHT * 3/8)
662 duelbutton = Button('(d)uel mode', WINDOWWIDTH / 2, WINDOWHEIGHT * 4/8)
663 partybutton = Button('(p)arty mode', WINDOWWIDTH / 2, WINDOWHEIGHT * 5/8)
664 instructbutton = Button('(i)nstructions', WINDOWWIDTH / 2, WINDOWHEIGHT * 6/8)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
665
666 while True: ### need to update this
667
668 DISPLAYSURF.fill(BGCOLOR)
669 DISPLAYSURF.blit(titleSurf, titleRect)
670 arcadebutton.display()
671 duelbutton.display()
9504e62 @djrahl added party mode.
authored
672 partybutton.display()
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
673 instructbutton.display()
674
675 for event in pygame.event.get():
676 if event.type == QUIT:
677 terminate()
678 elif event.type == MOUSEBUTTONDOWN:
679 mouse = pygame.mouse.get_pos()
680 if arcadebutton.pressed(mouse):
681 pygame.event.get()
682 runGame()
683 showGameOverScreen()
684 elif duelbutton.pressed(mouse):
685 pygame.event.get()
a734fdb @djrahl Added snake choices for duel mode.
authored
686 opponent = False
687 opponent = showSelectOpponentScreen()
688 if opponent != False:
689 runGame(10, 10, 9, opponent, True)
690 showGameOverScreen()
9504e62 @djrahl added party mode.
authored
691 elif partybutton.pressed(mouse):
692 pygame.event.get()
693 runGame(25, 5, 0, [LINUS, WIGGLES, GIGGLES], True)
694 showGameOverScreen()
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
695 elif instructbutton.pressed(mouse):
696 showInstructScreen()
697 elif event.type == KEYDOWN:
698 if event.key == K_a:
699 pygame.event.get()
700 runGame()
701 showGameOverScreen()
702 elif event.key == K_d:
703 pygame.event.get()
a734fdb @djrahl Added snake choices for duel mode.
authored
704 opponent = False
705 opponent = showSelectOpponentScreen()
706 if opponent != False:
707 runGame(10, 10, 9, opponent, True)
708 showGameOverScreen()
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
709 showGameOverScreen()
9504e62 @djrahl added party mode.
authored
710 elif event.key == K_p:
711 pygame.event.get()
712 runGame(25, 5, 0, [LINUS, WIGGLES, GIGGLES], True)
713 showGameOverScreen()
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
714 elif event.key == K_i:
715 showInstructScreen()
716 elif event.key == K_ESCAPE or event.key == K_q:
717 terminate()
718
719 pygame.display.update()
720 FPSCLOCK.tick(FPS)
9504e62 @djrahl added party mode.
authored
721
b68496b @djrahl first commit
authored
722
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
723 def runGame(speedTrigger=20, bonusTrigger=10, easyTrigger=19, opponents=[], twoApples=False):
b68496b @djrahl first commit
authored
724
6d8cfaf @djrahl set-up ai
authored
725 # in game variables
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
726 allsnake = []
727 allfruit = []
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
728 gametally = Tally(speedTrigger, bonusTrigger, easyTrigger)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
729
b68496b @djrahl first commit
authored
730 # create player snake and add to all snakes
6d8cfaf @djrahl set-up ai
authored
731 player = Snake('snakey', [{'x':5, 'y':5},{'x':4, 'y':5},{'x':3, 'y':5}], RIGHT, GREEN, COBALTGREEN)
b68496b @djrahl first commit
authored
732 allsnake.append(player)
733
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
734 for snake in opponents:
735 if snake == WIGGLES:
a734fdb @djrahl Added snake choices for duel mode.
authored
736 bakey = Opponent(WIGGLES, [{'x':CELLWIDTH-5, 'y':5},{'x':CELLWIDTH-4, 'y':5},{'x':CELLWIDTH-3, 'y':5}], LEFT, OLIVEGREEN, PURPLE, 20, 5)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
737 allsnake.append(bakey)
738 elif snake == GIGGLES:
a734fdb @djrahl Added snake choices for duel mode.
authored
739 wakey = Opponent(GIGGLES, [{'x':5, 'y':CELLHEIGHT-5},{'x':4, 'y':CELLHEIGHT-5},{'x':3, 'y':CELLHEIGHT-5}], RIGHT, PURPLE, EMERALDGREEN, 10, 10)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
740 allsnake.append(wakey)
741 elif snake == LINUS:
a734fdb @djrahl Added snake choices for duel mode.
authored
742 linus = Opponent(LINUS, [{'x':CELLWIDTH-5, 'y':CELLHEIGHT-5},{'x':CELLWIDTH-4, 'y':CELLHEIGHT-5},{'x':CELLWIDTH-3, 'y':CELLHEIGHT-5}], LEFT, IVORY, COBALTGREEN, 5, 20)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
743 allsnake.append(linus)
6d8cfaf @djrahl set-up ai
authored
744
b68496b @djrahl first commit
authored
745 # set beginning variables
746 player.player = True
747 player.score = 10
748 basespeed = FPS
749 currentspeed = basespeed
750 slowtimer = 0
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
751 nextEvent = 0
b68496b @djrahl first commit
authored
752
753 # create initial fruit
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
754 a = Apple(allfruit, allsnake, gametally)
b68496b @djrahl first commit
authored
755 allfruit.append(a)
2199376 @djrahl changed intro menu; added arcade mode & duel mode.
authored
756
757 # add second apple if applicable
758 if twoApples:
759 b = Apple(allfruit, allsnake, gametally)
760 allfruit.append(b)
761
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
762 # main game loop
763 while True:
6d8cfaf @djrahl set-up ai
authored
764 # event handling loop -- get player's direction choice
b68496b @djrahl first commit
authored
765 stop = False
6d8cfaf @djrahl set-up ai
authored
766
767 # get grid representation for AIs
768 grid = getGrid(allsnake, allfruit)
769
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
770 # get events in queue. This updates players direction and other key instructions (quit, debug...)
771 # if the next event after direction update suggests sharp direction change, following direction is stored.
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
772 for event in pygame.event.get():
b68496b @djrahl first commit
authored
773 if event.type == QUIT:
774 terminate()
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
775 elif nextEvent != 0:
776 player.direction = nextEvent
777 nextEvent = 0
778 stop = True
b68496b @djrahl first commit
authored
779 elif event.type == KEYDOWN and stop == False:
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
780 if event.key == K_LEFT and player.direction != RIGHT:
6d8cfaf @djrahl set-up ai
authored
781 player.direction = LEFT
b68496b @djrahl first commit
authored
782 stop = True
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
783 elif event.key == K_RIGHT and player.direction != LEFT:
6d8cfaf @djrahl set-up ai
authored
784 player.direction = RIGHT
b68496b @djrahl first commit
authored
785 stop = True
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
786 elif event.key == K_UP and player.direction != DOWN:
6d8cfaf @djrahl set-up ai
authored
787 player.direction = UP
b68496b @djrahl first commit
authored
788 stop = True
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
789 elif event.key == K_DOWN and player.direction != UP:
6d8cfaf @djrahl set-up ai
authored
790 player.direction = DOWN
b68496b @djrahl first commit
authored
791 stop = True
792 elif event.key == K_ESCAPE or event.key == K_q:
793 terminate()
6d8cfaf @djrahl set-up ai
authored
794 elif event.key == K_g and DEBUG == True:
795 debugPrintGrid(grid)
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
796 # peak into very next event. If key suggests sharp direction change, store in nextEvent
797 elif event.type == KEYDOWN and nextEvent == 0:
798 if event.key == K_LEFT and player.direction != RIGHT:
799 nextEvent = LEFT
800 elif event.key == K_RIGHT and player.direction != LEFT:
801 nextEvent = RIGHT
802 elif event.key == K_UP and player.direction != DOWN:
803 nextEvent = UP
804 elif event.key == K_DOWN and player.direction != UP:
805 nextEvent = DOWN
806 elif event.key == K_ESCAPE or event.key == K_q:
807 terminate()
808 elif event.key == K_g and DEBUG == True:
809 debugPrintGrid(grid)
6d8cfaf @djrahl set-up ai
authored
810
811 if DEBUG == True:
812 debugPause()
813
814 # update all other snake's direction choice
815 for snake in allsnake:
816 if snake.alive and snake.player == False:
817 snake.updateDirection(grid)
b68496b @djrahl first commit
authored
818
6d8cfaf @djrahl set-up ai
authored
819 # collision detection
b68496b @djrahl first commit
authored
820 for snake in allsnake:
6d8cfaf @djrahl set-up ai
authored
821 # check if the snake has hit boundary
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
822 if snake.alive and snake.boundsCollision():
b68496b @djrahl first commit
authored
823 snake.alive = False
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
824 # check if snake has hit another snake
825 for othersnake in allsnake:
826 if snake.alive and snake.snakeCollision(othersnake):
b68496b @djrahl first commit
authored
827 snake.alive = False
828
829 # check score - change color accordingly
830 # only looks at player snake
831 if player.score > 2000:
832 player.color = SIENNA
833 player.colorBorder = CORAL
834 elif player.score > 1500:
835 player.color = CORAL
836 player.colorBorder = GOLDENROD
837 elif player.score > 1250:
838 player.color = GOLDENROD
839 player.colorBorder = EMERALDGREEN
840 elif player.score > 1000:
841 player.color = KHAKI
842 player.colorBorder = LIGHTYELLOW
843 elif player.score > 750:
844 player.color = YELLOW
845 player.colorBorder = GREEN
846 elif player.score > 500:
847 player.color = LIGHTYELLOW
848 player.colorBorder = FORESTGREEN
849 elif player.score > 400:
850 player.color = IVORY #change this
851 player.colorBorder = FORESTGREEN
852 elif player.score > 300:
853 player.color = GREENYELLOW
854 player.colorBorder = OLIVEGREEN
855 elif player.score > 200:
856 player.color = HONEYDEW
857 player.colorBorder = SEAGREEN
858 elif player.score > 100:
859 player.color = SEAGREEN
860 player.colorBorder = EMERALDGREEN
861 else:
862 player.color = GREEN
863 player.colorBorder = COBALTGREEN
864
865 # check if fruit has been eaten by a snake
866 for snake in allsnake:
867 for fruit in allfruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
868 if snake.alive and snake.fruitCollision(fruit):
869 fruit.isEaten(snake, gametally)
870 # apples have special adding properties
871 if fruit.__class__ == Apple:
b68496b @djrahl first commit
authored
872 # check for speed increase
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
873 if gametally.checkSpeedTrigger():
b68496b @djrahl first commit
authored
874 basespeed = basespeed + 1
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
875 # check for bonus drop
876 if gametally.checkBonusTrigger():
877 bonus = gametally.runBonus()
6c613da @djrahl Worked on AI; added crude apple detection.
authored
878 for bonusfruit in bonus: #maybe try f = fruit.__class__()
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
879 if bonusfruit == 'poison':
880 f = Poison(allfruit, allsnake, gametally)
881 elif bonusfruit == 'orange':
882 f = Orange(allfruit, allsnake, gametally)
883 elif bonusfruit == 'raspberry':
884 f = Raspberry(allfruit, allsnake, gametally)
885 elif bonusfruit == 'blueberry':
886 f = Blueberry(allfruit, allsnake, gametally)
887 else:
888 f = Lemon(allfruit, allsnake, gametally)
889 allfruit.append(f)
890 # chance of poison drop
b68496b @djrahl first commit
authored
891 if random.randint(1,4) == 1:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
892 p = Poison(allfruit, allsnake, gametally)
b68496b @djrahl first commit
authored
893 allfruit.append(p)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
894 # chance of orange drop
b68496b @djrahl first commit
authored
895 if random.randint(1,5) == 1:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
896 o = Orange(allfruit, allsnake, gametally)
b68496b @djrahl first commit
authored
897 allfruit.append(o)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
898 # chance of raspberry drop
b68496b @djrahl first commit
authored
899 if random.randint(1,6) == 1:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
900 r = Raspberry(allfruit, allsnake, gametally)
b68496b @djrahl first commit
authored
901 allfruit.append(r)
902 # create new apple
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
903 a = Apple(allfruit, allsnake, gametally)
b68496b @djrahl first commit
authored
904 allfruit.append(a)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
905 elif fruit.__class__ == Blueberry:
906 # update speed
b68496b @djrahl first commit
authored
907 slowtimer = slowtimer + currentspeed * 12 # add 12 seconds
908 # remove fruit
909 allfruit.remove(fruit)
910
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
911 # check for snake death
b68496b @djrahl first commit
authored
912 for snake in allsnake:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
913 if snake.alive == False:
914 if snake.player == True:
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
915 showGameStats(allsnake)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
916 return 1
917
918 # check for size changes / move snake
919 for snake in allsnake:
920 snake.move()
b68496b @djrahl first commit
authored
921
922 # check multiplier and adjust color and multiplier as needed
923 for snake in allsnake:
924 if snake.multipliertimer > 0:
925 snake.multipliertimer = snake.multipliertimer - 1
4ae7881 @djrahl Fixed grid and snake color changes.
authored
926 snake.colorBorderCurrent = PURPLE
b68496b @djrahl first commit
authored
927 else:
4ae7881 @djrahl Fixed grid and snake color changes.
authored
928 # make sure multiplier is 1, color is normal
b68496b @djrahl first commit
authored
929 snake.multiplier = 1
4ae7881 @djrahl Fixed grid and snake color changes.
authored
930 snake.colorBorderCurrent = snake.colorBorder
b68496b @djrahl first commit
authored
931
932 # check slow and adjust color and fps as needed
933 if slowtimer > 0:
934 slowtimer = slowtimer - 1
935 for snake in allsnake:
4ae7881 @djrahl Fixed grid and snake color changes.
authored
936 snake.colorCurrent = BLUE
b68496b @djrahl first commit
authored
937 if currentspeed > 8:
938 currentspeed = currentspeed - 1
939 else:
940 if currentspeed < basespeed:
941 currentspeed = currentspeed + 1
4ae7881 @djrahl Fixed grid and snake color changes.
authored
942 # make sure color is normal
943 for snake in allsnake:
944 snake.colorCurrent = snake.color
b68496b @djrahl first commit
authored
945
946 # update timers on fruits, remove if necessary
947 for fruit in allfruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
948 if fruit.__class__ != Apple:
949 if fruit.updateTimer() == False:
b68496b @djrahl first commit
authored
950 allfruit.remove(fruit)
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
951
b68496b @djrahl first commit
authored
952 DISPLAYSURF.fill(BGCOLOR)
953 drawGrid()
954 for fruit in allfruit:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
955 fruit.drawFruit()
b68496b @djrahl first commit
authored
956 for snake in allsnake:
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
957 snake.drawSnake()
6d8cfaf @djrahl set-up ai
authored
958
959 # print scores
960 position = 1
961 for snake in allsnake:
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
962 snake.drawScore(position, allsnake)
6d8cfaf @djrahl set-up ai
authored
963 position = position + 1
b68496b @djrahl first commit
authored
964 pygame.display.update()
965 FPSCLOCK.tick(currentspeed)
966
967
968 def drawPressKeyMsg():
6c613da @djrahl Worked on AI; added crude apple detection.
authored
969 pressKeySurf = BASICFONT.render('Press any key to continue.', True, DARKGRAY)
b68496b @djrahl first commit
authored
970 pressKeyRect = pressKeySurf.get_rect()
971 pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
972 DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
973
974
975 def checkForKeyPress():
976 if len(pygame.event.get(QUIT)) > 0:
977 terminate()
978
979 keyUpEvents = pygame.event.get(KEYUP)
980 if len(keyUpEvents) == 0:
981 return None
982 if keyUpEvents[0].key == K_ESCAPE or keyUpEvents[0].key == K_q:
983 terminate()
984 return keyUpEvents[0].key
985
986
a734fdb @djrahl Added snake choices for duel mode.
authored
987 def showSelectOpponentScreen():
988 """
989 Blits opponent select onto screen. Returns opponent selected.
990 """
991 opponentlinusbutton = Button('(l)inus', WINDOWWIDTH / 2, WINDOWHEIGHT * 2/6)
992 opponentwigglesbutton = Button('(w)iggles', WINDOWWIDTH / 2, WINDOWHEIGHT * 3/6)
993 opponentgigglesbutton = Button('(g)iggles', WINDOWWIDTH / 2, WINDOWHEIGHT * 4/6)
994 cancelbutton = Button('(e)xit', WINDOWWIDTH / 2, WINDOWHEIGHT * 5/6)
995
996 while True:
997
998 choiceFont = pygame.font.Font('freesansbold.ttf', 36)
999 choiceSurf = choiceFont.render('Choose Opponent:', True, WHITE, FORESTGREEN)
1000 choiceRect = choiceSurf.get_rect()
1001
1002 DISPLAYSURF.fill(BGCOLOR)
1003 DISPLAYSURF.blit(choiceSurf, choiceRect)
1004
1005 opponentlinusbutton.display()
1006 opponentwigglesbutton.display()
1007 opponentgigglesbutton.display()
1008 cancelbutton.display()
1009
1010 for event in pygame.event.get():
1011 if event.type == QUIT:
1012 terminate()
1013 elif event.type == MOUSEBUTTONDOWN:
1014 mouse = pygame.mouse.get_pos()
1015 if opponentlinusbutton.pressed(mouse):
1016 pygame.event.get()
1017 return [LINUS]
1018 elif opponentwigglesbutton.pressed(mouse):
1019 pygame.event.get()
1020 return [WIGGLES]
1021 elif opponentgigglesbutton.pressed(mouse):
1022 pygame.event.get()
1023 return [GIGGLES]
1024 elif event.type == KEYDOWN:
1025 if event.key == K_l:
1026 pygame.event.get()
1027 return [LINUS]
1028 elif event.key == K_w:
1029 pygame.event.get()
1030 return [WIGGLES]
1031 elif event.key == K_g:
1032 pygame.event.get()
1033 return [GIGGLES]
1034 elif event.key == K_e:
1035 pygame.event.get()
1036 return False
1037 elif event.key == K_ESCAPE or event.key == K_q:
1038 terminate()
1039
1040 pygame.display.update()
1041
1042
b68496b @djrahl first commit
authored
1043 def showInstructScreen():
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1044 """
a734fdb @djrahl Added snake choices for duel mode.
authored
1045 Blits instructions onto screen. Returns when exit button clicked / key pressed.
1046 """
b68496b @djrahl first commit
authored
1047 endinstructbutton = Button('(e)xit', WINDOWWIDTH / 2, WINDOWHEIGHT - 40)
1048
1049 while True:
1050
1051 instruct = pygame.image.load('snakey_party_instructions.png').convert()
1052
1053 DISPLAYSURF.blit(instruct, (54, 10))
1054
1055 endinstructbutton.display()
1056
1057 for event in pygame.event.get():
1058 if event.type == QUIT:
1059 terminate()
1060 elif event.type == MOUSEBUTTONDOWN:
1061 mouse = pygame.mouse.get_pos()
1062 if endinstructbutton.pressed(mouse):
1063 pygame.event.get()
1064 return
1065 elif event.type == KEYDOWN:
1066 if event.key == K_e or event.key == K_i:
1067 pygame.event.get()
1068 return
1069 elif event.key == K_ESCAPE or event.key == K_q:
1070 terminate()
1071
1072 pygame.display.update()
1073
1074
1075 def terminate():
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1076 """
a734fdb @djrahl Added snake choices for duel mode.
authored
1077 Clean exit from pygame.
1078 """
b68496b @djrahl first commit
authored
1079 pygame.quit()
1080 sys.exit()
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1081
1082
1083 def showGameStats(allsnake):
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1084 """
a734fdb @djrahl Added snake choices for duel mode.
authored
1085 Displays game stats for all snakes at end of game.
1086 Returns when any key pressed.
1087 """
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1088 position = 1
1089 for snake in allsnake:
9504e62 @djrahl added party mode.
authored
1090 drawText('alive:', snake.alive, getPosition(position, allsnake), 25, snake.color)
1091 drawText('score:', snake.score, getPosition(position, allsnake), 45, snake.color)
1092 drawText('apples:', snake.fruitEaten['apple'], getPosition(position, allsnake), 65, RED)
1093 drawText('poison:', snake.fruitEaten['poison'], getPosition(position, allsnake), 85, GREEN)
1094 drawText('oranges:', snake.fruitEaten['orange'], getPosition(position, allsnake), 105, ORANGE)
1095 drawText('raspberries:', snake.fruitEaten['raspberry'], getPosition(position, allsnake), 125, PURPLE)
1096 drawText('blueberries:', snake.fruitEaten['blueberry'], getPosition(position, allsnake), 145, BLUE)
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1097 position = position + 1
1098
1099 drawPressKeyMsg()
1100 pygame.display.update()
a734fdb @djrahl Added snake choices for duel mode.
authored
1101 pygame.time.wait(200)
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1102 checkForKeyPress() # clear out any key presses in the event queue
1103
1104 while True:
1105 if checkForKeyPress():
1106 pygame.event.get() # clear event queue
1107 return
b68496b @djrahl first commit
authored
1108
1109
1110 def showGameOverScreen():
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1111 """
a734fdb @djrahl Added snake choices for duel mode.
authored
1112 Displays 'Game Over' message.
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1113 Returns when any key pressed.
a734fdb @djrahl Added snake choices for duel mode.
authored
1114 """
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1115 gameOverFont = pygame.font.Font('freesansbold.ttf', 120)
b68496b @djrahl first commit
authored
1116 gameSurf = gameOverFont.render('Game', True, WHITE)
1117 overSurf = gameOverFont.render('Over', True, WHITE)
1118 gameRect = gameSurf.get_rect()
1119 overRect = overSurf.get_rect()
1120 gameRect.midtop = (WINDOWWIDTH / 2, 10)
1121 overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)
1122
1123 DISPLAYSURF.blit(gameSurf, gameRect)
1124 DISPLAYSURF.blit(overSurf, overRect)
1125 drawPressKeyMsg()
1126 pygame.display.update()
a734fdb @djrahl Added snake choices for duel mode.
authored
1127 pygame.time.wait(200)
b68496b @djrahl first commit
authored
1128 checkForKeyPress() # clear out any key presses in the event queue
1129
1130 while True:
1131 if checkForKeyPress():
1132 pygame.event.get() # clear event queue
1133 return
1134
1135
6d8cfaf @djrahl set-up ai
authored
1136 def getGrid(allsnake, allfruit):
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1137 """
a734fdb @djrahl Added snake choices for duel mode.
authored
1138 Returns dictionary representation of all snakes and fruits on screen.
1139 Coordinates are entered as tuple (x,y).
1140 Used by AI when choosing best path.
1141 """
6d8cfaf @djrahl set-up ai
authored
1142 # refresh grid, dictionary representation of playing board used by AI
1143 grid = {(x,y):0 for x in range(CELLWIDTH) for y in range(CELLHEIGHT + (BUFFER / CELLSIZE))}
1144
1145 # add snakes to grid
1146 for snake in allsnake:
1147 for snakebody in snake.coords:
1148 grid[(snakebody['x'], snakebody['y'])] = 'snake'
6c613da @djrahl Worked on AI; added crude apple detection.
authored
1149
1150 # add fruits to grid
1151 for fruit in allfruit:
1152 if fruit.__class__ == Apple:
1153 grid[(fruit.coords['x'], fruit.coords['y'])] = 'apple'
1154
6d8cfaf @djrahl set-up ai
authored
1155 return grid
b68496b @djrahl first commit
authored
1156
1157
9504e62 @djrahl added party mode.
authored
1158 def drawText(text, value, x=1, y=1, color=WHITE, background=BLACK):
1159 scoreSurf = BASICFONT.render('%s %s' % (text, value), True, color, background)
b68496b @djrahl first commit
authored
1160 scoreRect = scoreSurf.get_rect()
faa87d1 @djrahl added Snake, Fruit, Tally classes
authored
1161 scoreRect.topleft = (x, y)
b68496b @djrahl first commit
authored
1162 DISPLAYSURF.blit(scoreSurf, scoreRect)
1163
1164
6d8cfaf @djrahl set-up ai
authored
1165
b68496b @djrahl first commit
authored
1166 def drawGrid():
1167 for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines
6d8cfaf @djrahl set-up ai
authored
1168 pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, BUFFER), (x, WINDOWHEIGHT))
4ae7881 @djrahl Fixed grid and snake color changes.
authored
1169 for y in range(BUFFER, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines
1170 pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))
6d8cfaf @djrahl set-up ai
authored
1171
1172
1173 def debugPause():
1174 while True:
1175 if checkForKeyPress():
1176 return
1177
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1178
6d8cfaf @djrahl set-up ai
authored
1179 def debugPrintGrid(grid):
1180 x = 0
1181 y = 0
1182 line = ""
1183 while grid.has_key((0,y)):
1184 if grid.has_key((x,y)):
1185 line = line + str(grid[(x,y)])[0]
1186 x = x + 1
1187 else:
1188 print line
1189 line = ""
1190 y = y + 1
1191 x = 0
b68496b @djrahl first commit
authored
1192
1193
4b2744c @djrahl added post-game tally, added event handling for sharp turns
authored
1194 def getPosition(position, allsnake):
1195 return (WINDOWWIDTH - (float(position) / float(len(allsnake)) * WINDOWWIDTH))
1196
1197
b68496b @djrahl first commit
authored
1198 if __name__ == '__main__':
1199 main()
1200
Something went wrong with that request. Please try again.