├── LICENSE
├── README.md
├── images
├── snaky_.gif
├── snaky_ai_v1.gif
├── snaky_ai_v2.gif
└── snaky_ai_v3.gif
├── snaky.py
├── snaky_ai_v1.py
├── snaky_ai_v2.py
└── snaky_ai_v3.py
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Guodong Xu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Snaky
2 |
3 | Snaky is a Snake game series including a basic one-player version and three versions of AI to play Snake automatically.
4 |
5 | The project is implemented in Python.
6 |
7 | **If you like it, Please give it a star, Thanks!**
8 | ### Require
9 |
10 | You should have `pygame` module installed.
11 |
12 | ### Final Version Demo
13 |
14 |
15 |
16 | ## Usage
17 |
18 | ### Basic function - One player
19 |
20 | In this version, you can control the movement of the snake to eat the apple to grow.
21 |
22 | ```bash
23 | git clone https://github.com/memoiry/Snaky
24 | cd Snaky
25 | python snaky.py
26 | ```
27 |
28 |
29 |
30 | It was actually manually controlled by myself(hard to control while recording the gif....so it's poor..)
31 |
32 |
33 |
34 |
35 | ### AI version 1 - Based on Hamiltonian path
36 |
37 | A perfect strategy, ensuring filling the screen, but the speed is slow.
38 |
39 | ```bash
40 | python snaky_ai_v1.py
41 | ```
42 |
43 |
44 |
45 |
46 | ### AI version 2 - Based on BFS
47 |
48 | A simple BFS strategy make the snake trapped in local optimal point and not considering future.
49 |
50 | ```bash
51 | python snaky_ai_v2.py
52 | ```
53 |
54 |
55 |
56 |
57 |
58 | ### AI version 3 - Based on BFS(shortest path), forward checking and follow the tail(longest path).
59 |
60 | In this AI version. The algorithm is constructed as follow.
61 |
62 | To find snake `S1`'s next moving direction `D`, the AI snake follows the steps below:
63 |
64 | 1. Compute the shortest path `P1` from snake `S1`'s head to the food. If `P1` exists, go to step 2. Otherwise, go to step 4.
65 | 2. Move a virtual snake `S2` (the same as `S1`) to eat the food along path `P1`.
66 | 3. Compute the longest path `P2` from snake `S2`'s head to its tail. If `P2` exists, let `D` be the first direction in path `P1`. Otherwise, go to step 4.
67 | 4. Compute the longest path `P3` from snake `S1`'s head to its tail. If `P3` exists, let D be the first direction in path `P3`. Otherwise, go to step 5.
68 | 5. Let `D` be the direction that makes the snake the farthest from the food.
69 |
70 | ```bash
71 | python snaky_ai_v3.py
72 | ```
73 |
74 |
75 |
76 |
77 | Enjoy!
78 |
79 | ## Reference
80 |
81 | [AutomatedSnakeGameSolvers.pdf](http://sites.uci.edu/joana1/files/2016/12/AutomatedSnakeGameSolvers)
82 |
83 | [Wormy](https://github.com/asweigart/making-games-with-python-and-pygame/blob/master/wormy/wormy.py)
84 |
85 |
--------------------------------------------------------------------------------
/images/snaky_.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/memoiry/Snaky/adba40f2a52879fa38881f6344934128160141ad/images/snaky_.gif
--------------------------------------------------------------------------------
/images/snaky_ai_v1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/memoiry/Snaky/adba40f2a52879fa38881f6344934128160141ad/images/snaky_ai_v1.gif
--------------------------------------------------------------------------------
/images/snaky_ai_v2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/memoiry/Snaky/adba40f2a52879fa38881f6344934128160141ad/images/snaky_ai_v2.gif
--------------------------------------------------------------------------------
/images/snaky_ai_v3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/memoiry/Snaky/adba40f2a52879fa38881f6344934128160141ad/images/snaky_ai_v3.gif
--------------------------------------------------------------------------------
/snaky.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import random, pygame, sys
4 | from pygame.locals import *
5 |
6 | FPS = 15
7 | ##WINDOWWIDTH = 640
8 | #WINDOWHEIGHT = 480
9 | WINDOWWIDTH = 640
10 | WINDOWHEIGHT = 480
11 | CELLSIZE = 40
12 | assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
13 | assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size."
14 | CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
15 | CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
16 |
17 | # R G B
18 | WHITE = (255, 255, 255)
19 | BLACK = ( 0, 0, 0)
20 | RED = (255, 0, 0)
21 | GREEN = ( 0, 255, 0)
22 | DARKGREEN = ( 0, 155, 0)
23 | DARKGRAY = ( 40, 40, 40)
24 | BGCOLOR = BLACK
25 |
26 | UP = 'up'
27 | DOWN = 'down'
28 | LEFT = 'left'
29 | RIGHT = 'right'
30 |
31 | HEAD = 0 # syntactic sugar: index of the worm's head
32 |
33 | def main():
34 | global FPSCLOCK, DISPLAYSURF, BASICFONT
35 |
36 | pygame.init()
37 | FPSCLOCK = pygame.time.Clock()
38 | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
39 | BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
40 | pygame.display.set_caption('Snaky')
41 |
42 | showStartScreen()
43 | while True:
44 | runGame()
45 | showGameOverScreen()
46 |
47 |
48 | def runGame():
49 | # Set a random start point.
50 | startx = random.randint(5, CELLWIDTH - 6)
51 | starty = random.randint(5, CELLHEIGHT - 6)
52 | wormCoords = [{'x': startx, 'y': starty},
53 | {'x': startx - 1, 'y': starty},
54 | {'x': startx - 2, 'y': starty}]
55 | direction = RIGHT
56 |
57 | # Start the apple in a random place.
58 | apple = getRandomLocation(wormCoords)
59 |
60 | while True: # main game loop
61 | pre_direction = direction
62 | for event in pygame.event.get(): # event handling loop
63 | if event.type == QUIT:
64 | terminate()
65 | elif event.type == KEYDOWN:
66 | if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
67 | direction = LEFT
68 | elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
69 | direction = RIGHT
70 | elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
71 | direction = UP
72 | elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
73 | direction = DOWN
74 | elif event.key == K_ESCAPE:
75 | terminate()
76 | # check if the worm has hit itself or the edge
77 | if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT:
78 | return # game over
79 | for wormBody in wormCoords[1:]:
80 | if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']:
81 | return # game over
82 |
83 | # check if worm has eaten an apply
84 | if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
85 | # don't remove worm's tail segment
86 | apple = getRandomLocation(wormCoords) # set a new apple somewhere
87 | else:
88 | del wormCoords[-1] # remove worm's tail segment
89 |
90 | # move the worm by adding a segment in the direction it is moving
91 | if not examine_direction(direction, pre_direction):
92 | direction = pre_direction
93 | if direction == UP:
94 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
95 | elif direction == DOWN:
96 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
97 | elif direction == LEFT:
98 | newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
99 | elif direction == RIGHT:
100 | newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
101 | wormCoords.insert(0, newHead)
102 | DISPLAYSURF.fill(BGCOLOR)
103 | drawGrid()
104 | drawWorm(wormCoords)
105 | drawApple(apple)
106 | drawScore(len(wormCoords) - 3)
107 | pygame.display.update()
108 | FPSCLOCK.tick(FPS)
109 |
110 | def examine_direction(temp , direction):
111 | if direction == UP:
112 | if temp == DOWN:
113 | return False
114 | elif direction == RIGHT:
115 | if temp == LEFT:
116 | return False
117 | elif direction == LEFT:
118 | if temp == RIGHT:
119 | return False
120 | elif direction == DOWN:
121 | if temp == UP:
122 | return False
123 | return True
124 |
125 | def drawPressKeyMsg():
126 | pressKeySurf = BASICFONT.render('Press a key to play.', True, DARKGRAY)
127 | pressKeyRect = pressKeySurf.get_rect()
128 | pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
129 | DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
130 |
131 |
132 | def checkForKeyPress():
133 | if len(pygame.event.get(QUIT)) > 0:
134 | terminate()
135 |
136 | keyUpEvents = pygame.event.get(KEYUP)
137 | if len(keyUpEvents) == 0:
138 | return None
139 | if keyUpEvents[0].key == K_ESCAPE:
140 | terminate()
141 | return keyUpEvents[0].key
142 |
143 |
144 | def showStartScreen():
145 | titleFont = pygame.font.Font('freesansbold.ttf', 100)
146 | titleSurf1 = titleFont.render('Snaky!', True, WHITE, DARKGREEN)
147 | titleSurf2 = titleFont.render('Snaky!', True, GREEN)
148 |
149 | degrees1 = 0
150 | degrees2 = 0
151 | while True:
152 | DISPLAYSURF.fill(BGCOLOR)
153 | rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
154 | rotatedRect1 = rotatedSurf1.get_rect()
155 | rotatedRect1.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
156 | DISPLAYSURF.blit(rotatedSurf1, rotatedRect1)
157 |
158 | rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
159 | rotatedRect2 = rotatedSurf2.get_rect()
160 | rotatedRect2.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
161 | DISPLAYSURF.blit(rotatedSurf2, rotatedRect2)
162 |
163 | drawPressKeyMsg()
164 |
165 | if checkForKeyPress():
166 | pygame.event.get() # clear event queue
167 | return
168 | pygame.display.update()
169 | FPSCLOCK.tick(FPS)
170 | degrees1 += 3 # rotate by 3 degrees each frame
171 | degrees2 += 7 # rotate by 7 degrees each frame
172 |
173 |
174 | def terminate():
175 | pygame.quit()
176 | sys.exit()
177 |
178 |
179 |
180 | def getRandomLocation(worm):
181 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
182 | while test_not_ok(temp, worm):
183 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
184 | return temp
185 |
186 | def test_not_ok(temp, worm):
187 | for body in worm:
188 | if temp['x'] == body['x'] and temp['y'] == body['y']:
189 | return True
190 | return False
191 |
192 | def showGameOverScreen():
193 | gameOverFont = pygame.font.Font('freesansbold.ttf', 150)
194 | gameSurf = gameOverFont.render('Game', True, WHITE)
195 | overSurf = gameOverFont.render('Over', True, WHITE)
196 | gameRect = gameSurf.get_rect()
197 | overRect = overSurf.get_rect()
198 | gameRect.midtop = (WINDOWWIDTH / 2, 10)
199 | overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)
200 |
201 | DISPLAYSURF.blit(gameSurf, gameRect)
202 | DISPLAYSURF.blit(overSurf, overRect)
203 | drawPressKeyMsg()
204 | pygame.display.update()
205 | pygame.time.wait(500)
206 | checkForKeyPress() # clear out any key presses in the event queue
207 |
208 | while True:
209 | if checkForKeyPress():
210 | pygame.event.get() # clear event queue
211 | return
212 |
213 | def drawScore(score):
214 | scoreSurf = BASICFONT.render('Score: %s' % (score), True, WHITE)
215 | scoreRect = scoreSurf.get_rect()
216 | scoreRect.topleft = (WINDOWWIDTH - 120, 10)
217 | DISPLAYSURF.blit(scoreSurf, scoreRect)
218 |
219 |
220 | def drawWorm(wormCoords):
221 | for coord in wormCoords:
222 | x = coord['x'] * CELLSIZE
223 | y = coord['y'] * CELLSIZE
224 | wormSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
225 | pygame.draw.rect(DISPLAYSURF, DARKGREEN, wormSegmentRect)
226 | wormInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
227 | pygame.draw.rect(DISPLAYSURF, GREEN, wormInnerSegmentRect)
228 |
229 |
230 | def drawApple(coord):
231 | x = coord['x'] * CELLSIZE
232 | y = coord['y'] * CELLSIZE
233 | appleRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
234 | pygame.draw.rect(DISPLAYSURF, RED, appleRect)
235 |
236 |
237 | def drawGrid():
238 | for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines
239 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT))
240 | for y in range(0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines
241 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))
242 |
243 |
244 | if __name__ == '__main__':
245 | main()
--------------------------------------------------------------------------------
/snaky_ai_v1.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | import random, pygame, sys
4 | from pygame.locals import *
5 |
6 | FPS = 80
7 | ##WINDOWWIDTH = 640
8 | #WINDOWHEIGHT = 480
9 | WINDOWWIDTH = 640
10 | WINDOWHEIGHT = 480
11 | CELLSIZE = 80
12 | assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
13 | assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size."
14 | CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
15 | CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
16 |
17 | # R G B
18 | WHITE = (255, 255, 255)
19 | BLACK = ( 0, 0, 0)
20 | RED = (255, 0, 0)
21 | GREEN = ( 0, 255, 0)
22 | DARKGREEN = ( 0, 155, 0)
23 | DARKGRAY = ( 40, 40, 40)
24 | BGCOLOR = BLACK
25 |
26 | UP = 'up'
27 | DOWN = 'down'
28 | LEFT = 'left'
29 | RIGHT = 'right'
30 |
31 | HEAD = 0 # syntactic sugar: index of the worm's head
32 |
33 | def main():
34 | global FPSCLOCK, DISPLAYSURF, BASICFONT
35 |
36 | pygame.init()
37 | FPSCLOCK = pygame.time.Clock()
38 | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
39 | BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
40 | pygame.display.set_caption('Snaky')
41 |
42 | showStartScreen()
43 | while True:
44 | runGame()
45 | showGameOverScreen()
46 |
47 | def get_direction(head_, last_direction):
48 | if head_['x'] == 1:
49 | if head_['y'] == CELLHEIGHT - 1:
50 | return LEFT
51 | elif head_['y'] == 0:
52 | return RIGHT
53 | if last_direction == LEFT:
54 | return DOWN
55 | elif last_direction == DOWN:
56 | return RIGHT
57 | elif head_['x'] >= 1 and head_['x'] <= CELLWIDTH-2:
58 | if last_direction == RIGHT:
59 | return RIGHT
60 | elif last_direction == LEFT:
61 | return LEFT
62 | elif head_['x'] == (CELLWIDTH-1):
63 | if last_direction == RIGHT:
64 | return DOWN
65 | elif last_direction == DOWN:
66 | return LEFT
67 | elif head_['x'] == 0:
68 | if head_['y'] != 0:
69 | return UP
70 | else:
71 | return RIGHT
72 |
73 |
74 | def runGame():
75 | # Set a random start point.
76 | startx = random.randint(0, CELLWIDTH -1)
77 | starty = random.randint(0, CELLHEIGHT -1)
78 | wormCoords = [{'x': startx, 'y': starty},
79 | {'x': startx - 1, 'y': starty},
80 | {'x': startx - 2, 'y': starty}]
81 | direction = RIGHT
82 |
83 | # Start the apple in a random place.
84 | apple = getRandomLocation(wormCoords)
85 |
86 | while True: # main game loop
87 | for event in pygame.event.get(): # event handling loop
88 | if event.type == QUIT:
89 | terminate()
90 | direction = get_direction(wormCoords[0], direction)
91 | # check if the worm has hit itself or the edge
92 | if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT:
93 | return # game over
94 | for wormBody in wormCoords[1:]:
95 | if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']:
96 | return # game over
97 |
98 | # check if worm has eaten an apply
99 | if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
100 | # don't remove worm's tail segment
101 | apple = getRandomLocation(wormCoords) # set a new apple somewhere
102 | else:
103 | del wormCoords[-1] # remove worm's tail segment
104 |
105 | # move the worm by adding a segment in the direction it is moving
106 | if direction == UP:
107 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
108 | elif direction == DOWN:
109 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
110 | elif direction == LEFT:
111 | newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
112 | elif direction == RIGHT:
113 | newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
114 | wormCoords.insert(0, newHead)
115 | DISPLAYSURF.fill(BGCOLOR)
116 | drawGrid()
117 | drawWorm(wormCoords)
118 | drawApple(apple)
119 | drawScore(len(wormCoords) - 3)
120 | pygame.display.update()
121 | FPSCLOCK.tick(FPS)
122 |
123 | def drawPressKeyMsg():
124 | pressKeySurf = BASICFONT.render('Press a key to play.', True, DARKGRAY)
125 | pressKeyRect = pressKeySurf.get_rect()
126 | pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
127 | DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
128 |
129 |
130 | def checkForKeyPress():
131 | if len(pygame.event.get(QUIT)) > 0:
132 | terminate()
133 |
134 | keyUpEvents = pygame.event.get(KEYUP)
135 | if len(keyUpEvents) == 0:
136 | return None
137 | if keyUpEvents[0].key == K_ESCAPE:
138 | terminate()
139 | return keyUpEvents[0].key
140 |
141 |
142 | def showStartScreen():
143 | titleFont = pygame.font.Font('freesansbold.ttf', 100)
144 | titleSurf1 = titleFont.render('Snaky!', True, WHITE, DARKGREEN)
145 | titleSurf2 = titleFont.render('Snaky!', True, GREEN)
146 |
147 | degrees1 = 0
148 | degrees2 = 0
149 | while True:
150 | DISPLAYSURF.fill(BGCOLOR)
151 | rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
152 | rotatedRect1 = rotatedSurf1.get_rect()
153 | rotatedRect1.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
154 | DISPLAYSURF.blit(rotatedSurf1, rotatedRect1)
155 |
156 | rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
157 | rotatedRect2 = rotatedSurf2.get_rect()
158 | rotatedRect2.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
159 | DISPLAYSURF.blit(rotatedSurf2, rotatedRect2)
160 |
161 | drawPressKeyMsg()
162 |
163 | if checkForKeyPress():
164 | pygame.event.get() # clear event queue
165 | return
166 | pygame.display.update()
167 | #FPSCLOCK.tick(FPS)
168 | degrees1 += 3 # rotate by 3 degrees each frame
169 | degrees2 += 7 # rotate by 7 degrees each frame
170 |
171 |
172 | def terminate():
173 | pygame.quit()
174 | sys.exit()
175 |
176 |
177 | def getRandomLocation(worm):
178 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
179 | while test_not_ok(temp, worm):
180 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
181 | return temp
182 |
183 | def test_not_ok(temp, worm):
184 | for body in worm:
185 | if temp['x'] == body['x'] and temp['y'] == body['y']:
186 | return True
187 | return False
188 |
189 |
190 | def showGameOverScreen():
191 | gameOverFont = pygame.font.Font('freesansbold.ttf', 150)
192 | gameSurf = gameOverFont.render('Game', True, WHITE)
193 | overSurf = gameOverFont.render('Over', True, WHITE)
194 | gameRect = gameSurf.get_rect()
195 | overRect = overSurf.get_rect()
196 | gameRect.midtop = (WINDOWWIDTH / 2, 10)
197 | overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)
198 |
199 | DISPLAYSURF.blit(gameSurf, gameRect)
200 | DISPLAYSURF.blit(overSurf, overRect)
201 | drawPressKeyMsg()
202 | pygame.display.update()
203 | pygame.time.wait(500)
204 | checkForKeyPress() # clear out any key presses in the event queue
205 |
206 | while True:
207 | if checkForKeyPress():
208 | pygame.event.get() # clear event queue
209 | return
210 |
211 | def drawScore(score):
212 | scoreSurf = BASICFONT.render('Score: %s' % (score), True, WHITE)
213 | scoreRect = scoreSurf.get_rect()
214 | scoreRect.topleft = (WINDOWWIDTH - 120, 10)
215 | DISPLAYSURF.blit(scoreSurf, scoreRect)
216 |
217 |
218 | def drawWorm(wormCoords):
219 | for coord in wormCoords:
220 | x = coord['x'] * CELLSIZE
221 | y = coord['y'] * CELLSIZE
222 | wormSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
223 | pygame.draw.rect(DISPLAYSURF, DARKGREEN, wormSegmentRect)
224 | wormInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
225 | pygame.draw.rect(DISPLAYSURF, GREEN, wormInnerSegmentRect)
226 |
227 |
228 | def drawApple(coord):
229 | x = coord['x'] * CELLSIZE
230 | y = coord['y'] * CELLSIZE
231 | appleRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
232 | pygame.draw.rect(DISPLAYSURF, RED, appleRect)
233 |
234 |
235 | def drawGrid():
236 | for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines
237 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT))
238 | for y in range(0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines
239 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))
240 |
241 |
242 | if __name__ == '__main__':
243 | main()
--------------------------------------------------------------------------------
/snaky_ai_v2.py:
--------------------------------------------------------------------------------
1 | import random, pygame, sys
2 | from pygame.locals import *
3 |
4 | FPS = 80
5 | ##WINDOWWIDTH = 640
6 | #WINDOWHEIGHT = 480
7 | WINDOWWIDTH = 600
8 | WINDOWHEIGHT = 480
9 | CELLSIZE = 40
10 | assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
11 | assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size."
12 | CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
13 | CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
14 |
15 | # R G B
16 | WHITE = (255, 255, 255)
17 | BLACK = ( 0, 0, 0)
18 | RED = (255, 0, 0)
19 | GREEN = ( 0, 255, 0)
20 | DARKGREEN = ( 0, 155, 0)
21 | DARKGRAY = ( 40, 40, 40)
22 | BGCOLOR = BLACK
23 |
24 |
25 | apple = {'x':0,'y':0}
26 |
27 | UP = 'up'
28 | DOWN = 'down'
29 | LEFT = 'left'
30 | RIGHT = 'right'
31 |
32 | direction = UP
33 | DIRECTION = [UP,DOWN,LEFT,RIGHT]
34 |
35 | HEAD = 0 # syntactic sugar: index of the worm's head
36 |
37 |
38 |
39 | distance = []
40 |
41 | for y in range(CELLHEIGHT):
42 | distance.append([])
43 | for x in range(CELLWIDTH):
44 | distance[y].append(8888)
45 |
46 | def into_queue((x, y), queue, visited, worm):
47 | if (x, y) == (apple['x'],apple['y']):
48 | return False
49 | elif x < 0 or x >= CELLWIDTH:
50 | return False
51 | elif y < 0 or y >= CELLHEIGHT:
52 | return False
53 | elif (x, y) in queue:
54 | return False
55 | elif (x, y) in visited:
56 | return False
57 | elif is_snake(x, y, worm):
58 | return False
59 | else:
60 | return True
61 |
62 | def is_snake(x,y,worm):
63 | for body in worm:
64 | if body['x'] == x and body['y'] == y:
65 | return True
66 | return False
67 |
68 |
69 | def cal_distance(worm):
70 | queue = [(apple['x'],apple['y'])]
71 | visited = []
72 | for y in range(CELLHEIGHT):
73 | for x in range(CELLWIDTH):
74 | distance[y][x] = 9999
75 |
76 | distance[apple['y']][apple['x']] = 0
77 |
78 | while len(queue) != 0:
79 | head = queue[0]
80 | visited.append(head)
81 | up_grid = head[0], head[1] - 1
82 | down_grid = head[0], head[1] + 1
83 | left_grid = head[0] - 1, head[1]
84 | right_grid = head[0] + 1, head[1]
85 |
86 | for grid in [up_grid, down_grid, left_grid, right_grid]:
87 | if into_queue(grid, queue, visited,worm):
88 | queue.append(grid)
89 | if distance[grid[1]][grid[0]] != 99999:
90 | distance[grid[1]][grid[0]] = distance[head[1]][head[0]] + 1
91 | queue.pop(0)
92 |
93 | def main():
94 | global FPSCLOCK, DISPLAYSURF, BASICFONT
95 |
96 | pygame.init()
97 | FPSCLOCK = pygame.time.Clock()
98 | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
99 | BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
100 | pygame.display.set_caption('Snaky')
101 |
102 | showStartScreen()
103 | while True:
104 | runGame()
105 | showGameOverScreen()
106 |
107 | def get_direction(head_, last_direction):
108 | if head_['x'] == 1:
109 | if head_['y'] == CELLHEIGHT - 1:
110 | return LEFT
111 | elif head_['y'] == 0:
112 | return RIGHT
113 | if last_direction == LEFT:
114 | return DOWN
115 | elif last_direction == DOWN:
116 | return RIGHT
117 | elif head_['x'] >= 1 and head_['x'] <= CELLWIDTH-2:
118 | if last_direction == RIGHT:
119 | return RIGHT
120 | elif last_direction == LEFT:
121 | return LEFT
122 | elif head_['x'] == (CELLWIDTH-1):
123 | if last_direction == RIGHT:
124 | return DOWN
125 | elif last_direction == DOWN:
126 | return LEFT
127 | elif head_['x'] == 0:
128 | if head_['y'] != 0:
129 | return UP
130 | else:
131 | return RIGHT
132 |
133 | def can_move((x, y), worm):
134 | if x < 0 or x >= CELLWIDTH:
135 | return False
136 | elif y < 0 or y >= CELLHEIGHT:
137 | return False
138 | elif is_snake(x, y,worm):
139 | return False
140 | elif (x, y) == (worm[HEAD]['x'], worm[HEAD]['y']):
141 | return False
142 | else:
143 | return True
144 |
145 | def test_not_ok(temp, worm):
146 | for body in worm:
147 | if temp['x'] == body['x'] and temp['y'] == body['y']:
148 | return True
149 | return False
150 |
151 | def update_dirc(now, direc):
152 | loc = {'x':0,'y':0}
153 | if direc == UP:
154 | loc = {'x':now['x'],'y':now['y']-1}
155 | elif direc == DOWN:
156 | loc = {'x':now['x'],'y':now['y']+1}
157 | elif direc == RIGHT:
158 | loc = {'x':now['x']+1,'y':now['y']}
159 | elif direc == LEFT:
160 | loc = {'x':now['x']-1,'y':now['y']}
161 | return loc
162 |
163 |
164 | def runGame():
165 | global running_,apple,DIRECTION
166 | # Set a random start point.
167 | startx = random.randint(0, CELLWIDTH -1)
168 | starty = random.randint(0, CELLHEIGHT -1)
169 | wormCoords = [{'x': startx, 'y': starty},
170 | {'x': startx - 1, 'y': starty},
171 | {'x': startx - 2, 'y': starty}]
172 | direction = RIGHT
173 | running_ = True
174 | # Start the apple in a random place.
175 | apple = getRandomLocation(wormCoords)
176 | cal_distance(wormCoords)
177 | while True: # main game loop
178 | for event in pygame.event.get(): # event handling loop
179 | if event.type == QUIT:
180 | terminate()
181 | four_dis = [99999, 99999, 99999, 99999]
182 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] - 1), wormCoords):
183 | four_dis[0] = distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']]
184 |
185 | if can_move((wormCoords[HEAD]['x'] + 1, wormCoords[HEAD]['y']), wormCoords):
186 | four_dis[1] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1]
187 |
188 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] + 1), wormCoords):
189 | four_dis[2] = distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']]
190 |
191 | if can_move((wormCoords[HEAD]['x'] - 1, wormCoords[HEAD]['y']), wormCoords):
192 | four_dis[3] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1]
193 |
194 | min_num = min(four_dis)
195 |
196 | if four_dis[0] < 99999 and distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']] == min_num and direction != DOWN:
197 | direction = UP
198 |
199 | elif four_dis[1] < 99999 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1] == min_num and direction != "LEFT":
200 | direction = RIGHT
201 |
202 | elif four_dis[2] < 99999 and distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']] == min_num and direction != "UP":
203 | direction = DOWN
204 |
205 | elif four_dis[3] < 99999 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1] == min_num and direction != RIGHT:
206 | direction = LEFT
207 |
208 | else:
209 | print direction
210 | index_ = 0
211 | for i in range(4):
212 | temp = update_dirc(wormCoords[HEAD],DIRECTION[i])
213 | if can_move(temp,wormCoords):
214 | index_ = i
215 | break
216 | direction_new = DIRECTION[index_]
217 | if direction == UP:
218 | if direction_new != DOWN:
219 | direction = direction_new
220 | elif direction == DOWN:
221 | if direction_new != UP:
222 | direction = direction_new
223 | elif direction == RIGHT:
224 | if direction_new != LEFT:
225 | direction = direction_new
226 | elif direction == LEFT:
227 | if direction_new != RIGHT:
228 | direction = direction_new
229 | print direction
230 | # check if the worm has hit itself or the edge
231 | if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT:
232 | return # game over
233 | for wormBody in wormCoords[1:]:
234 | if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']:
235 | return # game over
236 |
237 | # check if worm has eaten an apply
238 | if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
239 | # don't remove worm's tail segment
240 | apple = getRandomLocation(wormCoords) # set a new apple somewhere
241 | else:
242 | del wormCoords[-1] # remove worm's tail segment
243 |
244 | # move the worm by adding a segment in the direction it is moving
245 | if direction == UP:
246 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
247 | elif direction == DOWN:
248 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
249 | elif direction == LEFT:
250 | newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
251 | elif direction == RIGHT:
252 | newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
253 | wormCoords.insert(0, newHead)
254 | cal_distance(wormCoords)
255 | DISPLAYSURF.fill(BGCOLOR)
256 | drawGrid()
257 | drawWorm(wormCoords)
258 | drawApple(apple)
259 | drawScore(len(wormCoords) - 3)
260 | pygame.display.update()
261 | #FPSCLOCK.tick(FPS)
262 |
263 | def drawPressKeyMsg():
264 | pressKeySurf = BASICFONT.render('Press a key to play.', True, DARKGRAY)
265 | pressKeyRect = pressKeySurf.get_rect()
266 | pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
267 | DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
268 |
269 |
270 | def checkForKeyPress():
271 | if len(pygame.event.get(QUIT)) > 0:
272 | terminate()
273 |
274 | keyUpEvents = pygame.event.get(KEYUP)
275 | if len(keyUpEvents) == 0:
276 | return None
277 | if keyUpEvents[0].key == K_ESCAPE:
278 | terminate()
279 | return keyUpEvents[0].key
280 |
281 |
282 | def showStartScreen():
283 | titleFont = pygame.font.Font('freesansbold.ttf', 100)
284 | titleSurf1 = titleFont.render('Snaky!', True, WHITE, DARKGREEN)
285 | titleSurf2 = titleFont.render('Snaky!', True, GREEN)
286 |
287 | degrees1 = 0
288 | degrees2 = 0
289 | while True:
290 | DISPLAYSURF.fill(BGCOLOR)
291 | rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
292 | rotatedRect1 = rotatedSurf1.get_rect()
293 | rotatedRect1.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
294 | DISPLAYSURF.blit(rotatedSurf1, rotatedRect1)
295 |
296 | rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
297 | rotatedRect2 = rotatedSurf2.get_rect()
298 | rotatedRect2.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
299 | DISPLAYSURF.blit(rotatedSurf2, rotatedRect2)
300 |
301 | drawPressKeyMsg()
302 |
303 | if checkForKeyPress():
304 | pygame.event.get() # clear event queue
305 | return
306 | pygame.display.update()
307 | #FPSCLOCK.tick(FPS)
308 | degrees1 += 3 # rotate by 3 degrees each frame
309 | degrees2 += 7 # rotate by 7 degrees each frame
310 |
311 |
312 | def terminate():
313 | pygame.quit()
314 | sys.exit()
315 |
316 | def getRandomLocation(worm):
317 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
318 | while test_not_ok(temp, worm):
319 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
320 | return temp
321 |
322 |
323 | def showGameOverScreen():
324 | gameOverFont = pygame.font.Font('freesansbold.ttf', 150)
325 | gameSurf = gameOverFont.render('Game', True, WHITE)
326 | overSurf = gameOverFont.render('Over', True, WHITE)
327 | gameRect = gameSurf.get_rect()
328 | overRect = overSurf.get_rect()
329 | gameRect.midtop = (WINDOWWIDTH / 2, 10)
330 | overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)
331 |
332 | DISPLAYSURF.blit(gameSurf, gameRect)
333 | DISPLAYSURF.blit(overSurf, overRect)
334 | drawPressKeyMsg()
335 | pygame.display.update()
336 | pygame.time.wait(500)
337 | checkForKeyPress() # clear out any key presses in the event queue
338 |
339 | while True:
340 | if checkForKeyPress():
341 | pygame.event.get() # clear event queue
342 | return
343 |
344 | def drawScore(score):
345 | scoreSurf = BASICFONT.render('Score: %s' % (score), True, WHITE)
346 | scoreRect = scoreSurf.get_rect()
347 | scoreRect.topleft = (WINDOWWIDTH - 120, 10)
348 | DISPLAYSURF.blit(scoreSurf, scoreRect)
349 |
350 |
351 | def drawWorm(wormCoords):
352 | for coord in wormCoords:
353 | x = coord['x'] * CELLSIZE
354 | y = coord['y'] * CELLSIZE
355 | wormSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
356 | pygame.draw.rect(DISPLAYSURF, DARKGREEN, wormSegmentRect)
357 | wormInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
358 | pygame.draw.rect(DISPLAYSURF, GREEN, wormInnerSegmentRect)
359 |
360 |
361 | def drawApple(coord):
362 | x = coord['x'] * CELLSIZE
363 | y = coord['y'] * CELLSIZE
364 | appleRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
365 | pygame.draw.rect(DISPLAYSURF, RED, appleRect)
366 |
367 |
368 | def drawGrid():
369 | for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines
370 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT))
371 | for y in range(0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines
372 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))
373 |
374 | running_ = True
375 |
376 | if __name__ == '__main__':
377 | main()
--------------------------------------------------------------------------------
/snaky_ai_v3.py:
--------------------------------------------------------------------------------
1 | import random, pygame, sys
2 | from pygame.locals import *
3 |
4 | FPS = 100
5 | ##WINDOWWIDTH = 640
6 | #WINDOWHEIGHT = 480
7 | WINDOWWIDTH = 600
8 | WINDOWHEIGHT = 480
9 | CELLSIZE = 60
10 | assert WINDOWWIDTH % CELLSIZE == 0, "Window width must be a multiple of cell size."
11 | assert WINDOWHEIGHT % CELLSIZE == 0, "Window height must be a multiple of cell size."
12 | CELLWIDTH = int(WINDOWWIDTH / CELLSIZE)
13 | CELLHEIGHT = int(WINDOWHEIGHT / CELLSIZE)
14 |
15 | # R G B
16 | WHITE = (255, 255, 255)
17 | BLACK = ( 0, 0, 0)
18 | RED = (255, 0, 0)
19 | GREEN = ( 0, 255, 0)
20 | DARKGREEN = ( 0, 155, 0)
21 | DARKGRAY = ( 40, 40, 40)
22 | BGCOLOR = BLACK
23 |
24 |
25 |
26 | UP = 'up'
27 | DOWN = 'down'
28 | LEFT = 'left'
29 | RIGHT = 'right'
30 |
31 | direction = UP
32 | DIRECTION = [UP,DOWN,LEFT,RIGHT]
33 |
34 | HEAD = 0 # syntactic sugar: index of the worm's head
35 |
36 |
37 |
38 | distance = []
39 |
40 | for y in range(CELLHEIGHT):
41 | distance.append([])
42 | for x in range(CELLWIDTH):
43 | distance[y].append(8888)
44 |
45 | def into_queue((x, y), queue, visited, worm,apple):
46 | if (x, y) == (apple['x'],apple['y']):
47 | return False
48 | elif x < 0 or x >= CELLWIDTH:
49 | return False
50 | elif y < 0 or y >= CELLHEIGHT:
51 | return False
52 | elif (x, y) in queue:
53 | return False
54 | elif (x, y) in visited:
55 | return False
56 | else:
57 | return True
58 |
59 | def is_snake(x,y,worm):
60 | for body in worm:
61 | if body['x'] == x and body['y'] == y:
62 | return True
63 | return False
64 |
65 |
66 | def cal_distance(worm,apple):
67 | queue = [(apple['x'],apple['y'])]
68 | visited = []
69 | found = False
70 | for y in range(CELLHEIGHT):
71 | for x in range(CELLWIDTH):
72 | distance[y][x] = 9999
73 |
74 | distance[apple['y']][apple['x']] = 0
75 |
76 | while len(queue) != 0:
77 | head = queue[0]
78 | visited.append(head)
79 | up_grid = head[0], head[1] - 1
80 | down_grid = head[0], head[1] + 1
81 | left_grid = head[0] - 1, head[1]
82 | right_grid = head[0] + 1, head[1]
83 |
84 | for grid in [up_grid, down_grid, left_grid, right_grid]:
85 | if into_queue(grid, queue, visited,worm,apple):
86 | if grid[0] == worm[HEAD]['x'] and grid[1] == worm[HEAD]['y']:
87 | found = True
88 | if not is_snake(grid[0],grid[1],worm):
89 | queue.append(grid)
90 | distance[grid[1]][grid[0]] = distance[head[1]][head[0]] + 1
91 | queue.pop(0)
92 | return found
93 |
94 | def main():
95 | global FPSCLOCK, DISPLAYSURF, BASICFONT
96 |
97 | pygame.init()
98 | FPSCLOCK = pygame.time.Clock()
99 | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
100 | BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
101 | pygame.display.set_caption('Snaky')
102 |
103 | showStartScreen()
104 | while True:
105 | runGame()
106 | showGameOverScreen()
107 |
108 | def can_move((x, y), worm):
109 | if x < 0 or x >= CELLWIDTH:
110 | return False
111 | elif y < 0 or y >= CELLHEIGHT:
112 | return False
113 | elif is_snake(x, y,worm):
114 | return False
115 | elif (x, y) == (worm[HEAD]['x'], worm[HEAD]['y']):
116 | return False
117 | else:
118 | return True
119 |
120 |
121 | def update_dirc(now, direc):
122 | loc = {'x':0,'y':0}
123 | if direc == UP:
124 | loc = {'x':now['x'],'y':now['y']-1}
125 | elif direc == DOWN:
126 | loc = {'x':now['x'],'y':now['y']+1}
127 | elif direc == RIGHT:
128 | loc = {'x':now['x']+1,'y':now['y']}
129 | elif direc == LEFT:
130 | loc = {'x':now['x']-1,'y':now['y']}
131 | return loc
132 |
133 | def virtual_run(wormCoords, apple,direction):
134 | wormCoords = list(wormCoords)
135 | food_eated = False
136 | while not food_eated:
137 | cal_distance(wormCoords,apple)
138 | four_dis = [99999, 99999, 99999, 99999]
139 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] - 1), wormCoords):
140 | four_dis[0] = distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']]
141 |
142 | if can_move((wormCoords[HEAD]['x'] + 1, wormCoords[HEAD]['y']), wormCoords):
143 | four_dis[1] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1]
144 |
145 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] + 1), wormCoords):
146 | four_dis[2] = distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']]
147 |
148 | if can_move((wormCoords[HEAD]['x'] - 1, wormCoords[HEAD]['y']), wormCoords):
149 | four_dis[3] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1]
150 |
151 | min_num = min(four_dis)
152 |
153 | if four_dis[0] < 99999 and distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']] == min_num and direction != DOWN:
154 | direction = UP
155 |
156 | elif four_dis[1] < 99999 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1] == min_num and direction != "LEFT":
157 | direction = RIGHT
158 |
159 | elif four_dis[2] < 99999 and distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']] == min_num and direction != "UP":
160 | direction = DOWN
161 |
162 | elif four_dis[3] < 99999 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1] == min_num and direction != RIGHT:
163 | direction = LEFT
164 | if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT:
165 | return # game over
166 | for wormBody in wormCoords[1:]:
167 | if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']:
168 | return
169 |
170 | # move the worm by adding a segment in the direction it is moving
171 | if direction == UP:
172 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
173 | elif direction == DOWN:
174 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
175 | elif direction == LEFT:
176 | newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
177 | elif direction == RIGHT:
178 | newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
179 | if wormCoords[HEAD]['x'] != apple['x'] or wormCoords[HEAD]['y'] != apple['y']:
180 | food_eated = True
181 | wormCoords.insert(0, newHead)
182 | else:
183 | del wormCoords[-1] # remove worm's tail segment
184 | wormCoords.insert(0, newHead)
185 | result = cal_distance(wormCoords,wormCoords[-1])
186 | for i in range(4):
187 | temp = update_dirc(wormCoords[HEAD],DIRECTION[i])
188 | if temp['x'] == wormCoords[-1]['x'] and temp['y'] == wormCoords[-1]['y']:
189 | result = False
190 | return result
191 |
192 | def distance_(x,y):
193 | return abs(x['x']-y['x']) + abs(x['y'] - x['y'])
194 |
195 |
196 | def any_possible_move(worm,apple,direction):
197 | temp_direc = direction
198 | max_dis = 0
199 | for i in range(4):
200 | temp = update_dirc(worm[0],DIRECTION[i])
201 | if can_move((temp['x'],temp['y']),worm):
202 | if (distance_(temp, apple) > max_dis) and (examine_direction(DIRECTION[i], direction)):
203 | max_dis = distance_(temp, apple)
204 | temp_direc = DIRECTION[i]
205 | return temp_direc
206 |
207 | def examine_direction(temp , direction):
208 | if direction == UP:
209 | if temp == DOWN:
210 | return False
211 | elif direction == RIGHT:
212 | if temp == LEFT:
213 | return False
214 | elif direction == LEFT:
215 | if temp == RIGHT:
216 | return False
217 | elif direction == DOWN:
218 | if temp == UP:
219 | return False
220 | return True
221 |
222 | def check_head(worm,direction):
223 | for i in range(4):
224 | temp = update_dirc(worm[HEAD], DIRECTION[i])
225 | if can_move((temp['x'],temp['y']),worm) and examine_direction(DIRECTION[i],direction):
226 | if distance[temp['y']][temp['x']] < 9999:
227 | return True
228 | return False
229 |
230 |
231 | def runGame():
232 | global running_,DIRECTION
233 | # Set a random start point.
234 | startx = random.randint(0, CELLWIDTH -1)
235 | starty = random.randint(0, CELLHEIGHT -1)
236 | wormCoords = [{'x': startx, 'y': starty},
237 | {'x': startx - 1, 'y': starty},
238 | {'x': startx - 2, 'y': starty}]
239 | direction = RIGHT
240 | running_ = True
241 | # Start the apple in a random place.
242 | apple = getRandomLocation(wormCoords)
243 | count = 0
244 | while True: # main game loop
245 | for event in pygame.event.get(): # event handling loop
246 | if event.type == QUIT:
247 | terminate()
248 | new_direction = None
249 | #print distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x']]
250 | if cal_distance(wormCoords,apple):
251 | #print "Test"
252 | if virtual_run(wormCoords, apple, direction):
253 | cal_distance(wormCoords,apple)
254 | four_dis = [99999] * 4
255 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] - 1), wormCoords):
256 | four_dis[0] = distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']]
257 |
258 | if can_move((wormCoords[HEAD]['x'] + 1, wormCoords[HEAD]['y']), wormCoords):
259 | four_dis[1] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1]
260 |
261 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] + 1), wormCoords):
262 | four_dis[2] = distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']]
263 |
264 | if can_move((wormCoords[HEAD]['x'] - 1, wormCoords[HEAD]['y']), wormCoords):
265 | four_dis[3] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1]
266 |
267 | max_num = min(four_dis)
268 |
269 | if four_dis[0] < 99999 and distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']] == max_num and direction != DOWN:
270 | new_direction = UP
271 |
272 | elif four_dis[1] < 99999 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1] == max_num and direction != LEFT:
273 | new_direction = RIGHT
274 |
275 | elif four_dis[2] < 99999 and distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']] == max_num and direction != UP:
276 | new_direction = DOWN
277 |
278 | elif four_dis[3] < 99999 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1] == max_num and direction != RIGHT:
279 | new_direction = LEFT
280 | else:
281 | count += 1
282 | print count
283 | four_dis = [-1] * 4
284 | cal_distance(wormCoords, wormCoords[-1])
285 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] - 1), wormCoords):
286 | four_dis[0] = distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']]
287 |
288 | if can_move((wormCoords[HEAD]['x'] + 1, wormCoords[HEAD]['y']), wormCoords):
289 | four_dis[1] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1]
290 |
291 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] + 1), wormCoords):
292 | four_dis[2] = distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']]
293 |
294 | if can_move((wormCoords[HEAD]['x'] - 1, wormCoords[HEAD]['y']), wormCoords):
295 | four_dis[3] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1]
296 |
297 | max_num = 0
298 | for i in four_dis:
299 | if i != 9999:
300 | if i > max_num:
301 | max_num = i
302 |
303 | if four_dis[0] > -1 and distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']] == max_num and direction != DOWN:
304 | new_direction = UP
305 |
306 | elif four_dis[1] > -1 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1] == max_num and direction != LEFT:
307 | new_direction = RIGHT
308 |
309 | elif four_dis[2] > -1 and distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']] == max_num and direction != UP:
310 | new_direction = DOWN
311 |
312 | elif four_dis[3] > -1 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1] == max_num and direction != RIGHT:
313 | new_direction = LEFT
314 | if count == 10:
315 | new_direction = any_possible_move(wormCoords, apple, direction)
316 | count = 0
317 | else:
318 | four_dis = [-1] * 4
319 | cal_distance(wormCoords, wormCoords[-1])
320 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] - 1), wormCoords):
321 | four_dis[0] = distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']]
322 |
323 | if can_move((wormCoords[HEAD]['x'] + 1, wormCoords[HEAD]['y']), wormCoords):
324 | four_dis[1] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1]
325 |
326 | if can_move((wormCoords[HEAD]['x'], wormCoords[HEAD]['y'] + 1), wormCoords):
327 | four_dis[2] = distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']]
328 |
329 | if can_move((wormCoords[HEAD]['x'] - 1, wormCoords[HEAD]['y']), wormCoords):
330 | four_dis[3] = distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1]
331 |
332 | max_num = 0
333 | for i in four_dis:
334 | if i != 9999:
335 | if i > max_num:
336 | max_num = i
337 |
338 | if four_dis[0] > -1 and distance[wormCoords[HEAD]['y'] - 1][wormCoords[HEAD]['x']] == max_num and direction != DOWN:
339 | new_direction = UP
340 |
341 | elif four_dis[1] > -1 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] + 1] == max_num and direction != LEFT:
342 | new_direction = RIGHT
343 |
344 | elif four_dis[2] > -1 and distance[wormCoords[HEAD]['y'] + 1][wormCoords[HEAD]['x']] == max_num and direction != UP:
345 | new_direction = DOWN
346 |
347 | elif four_dis[3] > -1 and distance[wormCoords[HEAD]['y']][wormCoords[HEAD]['x'] - 1] == max_num and direction != RIGHT:
348 | new_direction = LEFT
349 | if new_direction == None:
350 | direction = any_possible_move(wormCoords, apple, direction)
351 | else:
352 | direction = new_direction
353 | #temp_ = update_dirc(wormCoords[HEAD],direction)
354 | #while not can_move((temp_['x'],temp_['y']), wormCoords):
355 | #direction = any_possible_move(wormCoords, apple, direction)
356 | # check if the worm has hit itself or the edge
357 | if wormCoords[HEAD]['x'] == -1 or wormCoords[HEAD]['x'] == CELLWIDTH or wormCoords[HEAD]['y'] == -1 or wormCoords[HEAD]['y'] == CELLHEIGHT:
358 | return # game over
359 | for wormBody in wormCoords[1:]:
360 | if wormBody['x'] == wormCoords[HEAD]['x'] and wormBody['y'] == wormCoords[HEAD]['y']:
361 | return # game over
362 |
363 | # check if worm has eaten an apply
364 | if wormCoords[HEAD]['x'] == apple['x'] and wormCoords[HEAD]['y'] == apple['y']:
365 | # don't remove worm's tail
366 | apple = getRandomLocation(wormCoords)
367 | else:
368 | del wormCoords[-1] # remove worm's tail segment
369 |
370 | # move the worm by adding a segment in the direction it is moving
371 | if direction == UP:
372 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] - 1}
373 | elif direction == DOWN:
374 | newHead = {'x': wormCoords[HEAD]['x'], 'y': wormCoords[HEAD]['y'] + 1}
375 | elif direction == LEFT:
376 | newHead = {'x': wormCoords[HEAD]['x'] - 1, 'y': wormCoords[HEAD]['y']}
377 | elif direction == RIGHT:
378 | newHead = {'x': wormCoords[HEAD]['x'] + 1, 'y': wormCoords[HEAD]['y']}
379 | wormCoords.insert(0, newHead) # set a new apple somewhere
380 | DISPLAYSURF.fill(BGCOLOR)
381 | drawGrid()
382 | drawWorm(wormCoords)
383 | drawApple(apple)
384 | drawScore(len(wormCoords) - 3)
385 | pygame.display.update()
386 | #FPSCLOCK.tick(FPS)
387 |
388 | def drawPressKeyMsg():
389 | pressKeySurf = BASICFONT.render('Press a key to play.', True, DARKGRAY)
390 | pressKeyRect = pressKeySurf.get_rect()
391 | pressKeyRect.topleft = (WINDOWWIDTH - 200, WINDOWHEIGHT - 30)
392 | DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
393 |
394 |
395 | def checkForKeyPress():
396 | if len(pygame.event.get(QUIT)) > 0:
397 | terminate()
398 |
399 | keyUpEvents = pygame.event.get(KEYUP)
400 | if len(keyUpEvents) == 0:
401 | return None
402 | if keyUpEvents[0].key == K_ESCAPE:
403 | terminate()
404 | return keyUpEvents[0].key
405 |
406 |
407 | def showStartScreen():
408 | titleFont = pygame.font.Font('freesansbold.ttf', 100)
409 | titleSurf1 = titleFont.render('Snaky!', True, WHITE, DARKGREEN)
410 | titleSurf2 = titleFont.render('Snaky!', True, GREEN)
411 |
412 | degrees1 = 0
413 | degrees2 = 0
414 | while True:
415 | DISPLAYSURF.fill(BGCOLOR)
416 | rotatedSurf1 = pygame.transform.rotate(titleSurf1, degrees1)
417 | rotatedRect1 = rotatedSurf1.get_rect()
418 | rotatedRect1.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
419 | DISPLAYSURF.blit(rotatedSurf1, rotatedRect1)
420 |
421 | rotatedSurf2 = pygame.transform.rotate(titleSurf2, degrees2)
422 | rotatedRect2 = rotatedSurf2.get_rect()
423 | rotatedRect2.center = (WINDOWWIDTH / 2, WINDOWHEIGHT / 2)
424 | DISPLAYSURF.blit(rotatedSurf2, rotatedRect2)
425 |
426 | drawPressKeyMsg()
427 |
428 | if checkForKeyPress():
429 | pygame.event.get() # clear event queue
430 | return
431 | pygame.display.update()
432 | FPSCLOCK.tick(FPS)
433 | degrees1 += 3 # rotate by 3 degrees each frame
434 | degrees2 += 7 # rotate by 7 degrees each frame
435 |
436 |
437 | def terminate():
438 | pygame.quit()
439 | sys.exit()
440 |
441 |
442 | def getRandomLocation(worm):
443 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
444 | while test_not_ok(temp, worm):
445 | temp = {'x': random.randint(0, CELLWIDTH - 1), 'y': random.randint(0, CELLHEIGHT - 1)}
446 | return temp
447 |
448 | def test_not_ok(temp, worm):
449 | for body in worm:
450 | if temp['x'] == body['x'] and temp['y'] == body['y']:
451 | return True
452 | return False
453 |
454 |
455 | def showGameOverScreen():
456 | gameOverFont = pygame.font.Font('freesansbold.ttf', 150)
457 | gameSurf = gameOverFont.render('Game', True, WHITE)
458 | overSurf = gameOverFont.render('Over', True, WHITE)
459 | gameRect = gameSurf.get_rect()
460 | overRect = overSurf.get_rect()
461 | gameRect.midtop = (WINDOWWIDTH / 2, 10)
462 | overRect.midtop = (WINDOWWIDTH / 2, gameRect.height + 10 + 25)
463 |
464 | DISPLAYSURF.blit(gameSurf, gameRect)
465 | DISPLAYSURF.blit(overSurf, overRect)
466 | drawPressKeyMsg()
467 | pygame.display.update()
468 | pygame.time.wait(500)
469 | checkForKeyPress() # clear out any key presses in the event queue
470 |
471 | while True:
472 | if checkForKeyPress():
473 | pygame.event.get() # clear event queue
474 | return
475 |
476 | def drawScore(score):
477 | scoreSurf = BASICFONT.render('Score: %s' % (score), True, WHITE)
478 | scoreRect = scoreSurf.get_rect()
479 | scoreRect.topleft = (WINDOWWIDTH - 120, 10)
480 | DISPLAYSURF.blit(scoreSurf, scoreRect)
481 |
482 |
483 | def drawWorm(wormCoords):
484 | for coord in wormCoords:
485 | x = coord['x'] * CELLSIZE
486 | y = coord['y'] * CELLSIZE
487 | wormSegmentRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
488 | pygame.draw.rect(DISPLAYSURF, DARKGREEN, wormSegmentRect)
489 | wormInnerSegmentRect = pygame.Rect(x + 4, y + 4, CELLSIZE - 8, CELLSIZE - 8)
490 | pygame.draw.rect(DISPLAYSURF, GREEN, wormInnerSegmentRect)
491 |
492 |
493 | def drawApple(coord):
494 | x = coord['x'] * CELLSIZE
495 | y = coord['y'] * CELLSIZE
496 | appleRect = pygame.Rect(x, y, CELLSIZE, CELLSIZE)
497 | pygame.draw.rect(DISPLAYSURF, RED, appleRect)
498 |
499 |
500 | def drawGrid():
501 | for x in range(0, WINDOWWIDTH, CELLSIZE): # draw vertical lines
502 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (x, 0), (x, WINDOWHEIGHT))
503 | for y in range(0, WINDOWHEIGHT, CELLSIZE): # draw horizontal lines
504 | pygame.draw.line(DISPLAYSURF, DARKGRAY, (0, y), (WINDOWWIDTH, y))
505 |
506 | running_ = True
507 |
508 | if __name__ == '__main__':
509 | main()
--------------------------------------------------------------------------------