Skip to content

HTTPS clone URL

Subversion checkout URL

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