├── 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() --------------------------------------------------------------------------------