| 1 | # Flippy (an Othello or Reversi clone) | 1 | # Flippy (an Othello or Reversi clone) |
| 2 | # By Al Sweigart al@inventwithpython.com | 2 | # By Al Sweigart al@inventwithpython.com |
| 3 | # http://inventwithpython.com/pygame | 3 | # http://inventwithpython.com/pygame |
| 4 | # Released under a "Simplified BSD" license | 4 | # Released under a "Simplified BSD" license |
| 5 | | 5 | |
| 6 | # Based on the "reversi.py" code that originally appeared in "Invent | 6 | # Based on the "reversi.py" code that originally appeared in "Invent |
| 7 | # Your Own Computer Games with Python", chapter 15: | 7 | # Your Own Computer Games with Python", chapter 15: |
| 8 | # http://inventwithpython.com/chapter15.html | 8 | # http://inventwithpython.com/chapter15.html |
| 9 | | 9 | |
| 10 | import random, sys, pygame, time, copy | 10 | import random, sys, pygame, time, copy |
| 11 | from pygame.locals import * | 11 | from pygame.locals import * |
| 12 | | 12 | |
| | | 13 | # NEW SAVE FEATURE CODE: |
| | | 14 | import shelve |
| | | 15 | |
| 13 | FPS = 10 # frames per second to update the screen | 16 | FPS = 10 # frames per second to update the screen |
| 14 | WINDOWWIDTH = 640 # width of the program's window, in pixels | 17 | WINDOWWIDTH = 640 # width of the program's window, in pixels |
| 15 | WINDOWHEIGHT = 480 # height in pixels | 18 | WINDOWHEIGHT = 480 # height in pixels |
| 16 | SPACESIZE = 50 # width & height of each space on the board, in pixels | 19 | SPACESIZE = 50 # width & height of each space on the board, in pixels |
| 17 | BOARDWIDTH = 8 # how many columns of spaces on the game board | 20 | BOARDWIDTH = 8 # how many columns of spaces on the game board |
| 18 | BOARDHEIGHT = 8 # how many rows of spaces on the game board | 21 | BOARDHEIGHT = 8 # how many rows of spaces on the game board |
| 19 | WHITE_TILE = 'WHITE_TILE' # an arbitrary but unique value | 22 | WHITE_TILE = 'WHITE_TILE' # an arbitrary but unique value |
| 20 | BLACK_TILE = 'BLACK_TILE' # an arbitrary but unique value | 23 | BLACK_TILE = 'BLACK_TILE' # an arbitrary but unique value |
| 21 | EMPTY_SPACE = 'EMPTY_SPACE' # an arbitrary but unique value | 24 | EMPTY_SPACE = 'EMPTY_SPACE' # an arbitrary but unique value |
| 22 | HINT_TILE = 'HINT_TILE' # an arbitrary but unique value | 25 | HINT_TILE = 'HINT_TILE' # an arbitrary but unique value |
| 23 | ANIMATIONSPEED = 25 # integer from 1 to 100, higher is faster animation | 26 | ANIMATIONSPEED = 25 # integer from 1 to 100, higher is faster animation |
| 24 | | 27 | |
| 25 | # Amount of space on the left & right side (XMARGIN) or above and below | 28 | # Amount of space on the left & right side (XMARGIN) or above and below |
| 26 | # (YMARGIN) the game board, in pixels. | 29 | # (YMARGIN) the game board, in pixels. |
| 27 | XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * SPACESIZE)) / 2) | 30 | XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * SPACESIZE)) / 2) |
| 28 | YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * SPACESIZE)) / 2) | 31 | YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * SPACESIZE)) / 2) |
| 29 | | 32 | |
| 30 | # R G B | 33 | # R G B |
| 31 | WHITE = (255, 255, 255) | 34 | WHITE = (255, 255, 255) |
| 32 | BLACK = ( 0, 0, 0) | 35 | BLACK = ( 0, 0, 0) |
| 33 | GREEN = ( 0, 155, 0) | 36 | GREEN = ( 0, 155, 0) |
| 34 | BRIGHTBLUE = ( 0, 50, 255) | 37 | BRIGHTBLUE = ( 0, 50, 255) |
| 35 | BROWN = (174, 94, 0) | 38 | BROWN = (174, 94, 0) |
| 36 | | 39 | |
| 37 | TEXTBGCOLOR1 = BRIGHTBLUE | 40 | TEXTBGCOLOR1 = BRIGHTBLUE |
| 38 | TEXTBGCOLOR2 = GREEN | 41 | TEXTBGCOLOR2 = GREEN |
| 39 | GRIDLINECOLOR = BLACK | 42 | GRIDLINECOLOR = BLACK |
| 40 | TEXTCOLOR = WHITE | 43 | TEXTCOLOR = WHITE |
| 41 | HINTCOLOR = BROWN | 44 | HINTCOLOR = BROWN |
| 42 | | 45 | |
| 43 | | 46 | |
| 44 | def main(): | 47 | def main(): |
| 45 | global MAINCLOCK, DISPLAYSURF, FONT, BIGFONT, BGIMAGE | 48 | global MAINCLOCK, DISPLAYSURF, FONT, BIGFONT, BGIMAGE |
| 46 | | 49 | |
| 47 | pygame.init() | 50 | pygame.init() |
| 48 | MAINCLOCK = pygame.time.Clock() | 51 | MAINCLOCK = pygame.time.Clock() |
| 49 | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) | 52 | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) |
| 50 | pygame.display.set_caption('Flippy') | 53 | pygame.display.set_caption('Flippy') |
| 51 | FONT = pygame.font.Font('freesansbold.ttf', 16) | 54 | FONT = pygame.font.Font('freesansbold.ttf', 16) |
| 52 | BIGFONT = pygame.font.Font('freesansbold.ttf', 32) | 55 | BIGFONT = pygame.font.Font('freesansbold.ttf', 32) |
| 53 | | 56 | |
| 54 | # Set up the background image. | 57 | # Set up the background image. |
| 55 | boardImage = pygame.image.load('flippyboard.png') | 58 | boardImage = pygame.image.load('flippyboard.png') |
| 56 | # Use smoothscale() to stretch the board image to fit the entire board: | 59 | # Use smoothscale() to stretch the board image to fit the entire board: |
| 57 | boardImage = pygame.transform.smoothscale(boardImage, (BOARDWIDTH * SPACESIZE, BOARDHEIGHT * SPACESIZE)) | 60 | boardImage = pygame.transform.smoothscale(boardImage, (BOARDWIDTH * SPACESIZE, BOARDHEIGHT * SPACESIZE)) |
| 58 | boardImageRect = boardImage.get_rect() | 61 | boardImageRect = boardImage.get_rect() |
| 59 | boardImageRect.topleft = (XMARGIN, YMARGIN) | 62 | boardImageRect.topleft = (XMARGIN, YMARGIN) |
| 60 | BGIMAGE = pygame.image.load('flippybackground.png') | 63 | BGIMAGE = pygame.image.load('flippybackground.png') |
| 61 | # Use smoothscale() to stretch the background image to fit the entire window: | 64 | # Use smoothscale() to stretch the background image to fit the entire window: |
| 62 | BGIMAGE = pygame.transform.smoothscale(BGIMAGE, (WINDOWWIDTH, WINDOWHEIGHT)) | 65 | BGIMAGE = pygame.transform.smoothscale(BGIMAGE, (WINDOWWIDTH, WINDOWHEIGHT)) |
| 63 | BGIMAGE.blit(boardImage, boardImageRect) | 66 | BGIMAGE.blit(boardImage, boardImageRect) |
| 64 | | 67 | |
| 65 | # Run the main game. | 68 | # Run the main game. |
| 66 | while True: | 69 | while True: |
| 67 | if runGame() == False: | 70 | if runGame() == False: |
| 68 | break | 71 | break |
| 69 | | 72 | |
| 70 | | 73 | |
| 71 | def runGame(): | 74 | def runGame(): |
| 72 | # Plays a single game of reversi each time this function is called. | 75 | # Plays a single game of reversi each time this function is called. |
| 73 | | 76 | |
| 74 | # Reset the board and game. | 77 | # Reset the board and game. |
| 75 | mainBoard = getNewBoard() | 78 | mainBoard = getNewBoard() |
| 76 | resetBoard(mainBoard) | 79 | resetBoard(mainBoard) |
| 77 | showHints = False | 80 | showHints = False |
| 78 | turn = random.choice(['computer', 'player']) | 81 | turn = random.choice(['computer', 'player']) |
| 79 | | 82 | |
| 80 | # Draw the starting board and ask the player what color they want. | 83 | # Draw the starting board and ask the player what color they want. |
| 81 | drawBoard(mainBoard) | 84 | drawBoard(mainBoard) |
| 82 | playerTile, computerTile = enterPlayerTile() | 85 | playerTile, computerTile = enterPlayerTile() |
| 83 | | 86 | |
| 84 | # Make the Surface and Rect objects for the "New Game" and "Hints" buttons | 87 | # Make the Surface and Rect objects for the "New Game" and "Hints" buttons |
| 85 | newGameSurf = FONT.render('New Game', True, TEXTCOLOR, TEXTBGCOLOR2) | 88 | newGameSurf = FONT.render('New Game', True, TEXTCOLOR, TEXTBGCOLOR2) |
| 86 | newGameRect = newGameSurf.get_rect() | 89 | newGameRect = newGameSurf.get_rect() |
| 87 | newGameRect.topright = (WINDOWWIDTH - 8, 10) | 90 | newGameRect.topright = (WINDOWWIDTH - 8, 10) |
| 88 | hintsSurf = FONT.render('Hints', True, TEXTCOLOR, TEXTBGCOLOR2) | 91 | hintsSurf = FONT.render('Hints', True, TEXTCOLOR, TEXTBGCOLOR2) |
| 89 | hintsRect = hintsSurf.get_rect() | 92 | hintsRect = hintsSurf.get_rect() |
| 90 | hintsRect.topright = (WINDOWWIDTH - 8, 40) | 93 | hintsRect.topright = (WINDOWWIDTH - 8, 40) |
| 91 | | 94 | |
| | | 95 | # NEW SAVE FEATURE CODE: |
| | | 96 | # Make the Surface and Rect objects for the "Save game" and "Load game" slots |
| | | 97 | saveButtonSurf = FONT.render('Save Game', True, TEXTCOLOR, TEXTBGCOLOR2) |
| | | 98 | saveButtonRect = saveButtonSurf.get_rect() |
| | | 99 | saveButtonRect.topright = (WINDOWWIDTH - 8, 70) |
| | | 100 | loadButtonSurf = FONT.render('Load Game', True, TEXTCOLOR, TEXTBGCOLOR2) |
| | | 101 | loadButtonRect = loadButtonSurf.get_rect() |
| | | 102 | loadButtonRect.topright = (WINDOWWIDTH - 8, 100) |
| | | 103 | |
| 92 | while True: # main game loop | 104 | while True: # main game loop |
| 93 | # Keep looping for player and computer's turns. | 105 | # Keep looping for player and computer's turns. |
| 94 | if turn == 'player': | 106 | if turn == 'player': |
| 95 | # Player's turn: | 107 | # Player's turn: |
| 96 | if getValidMoves(mainBoard, playerTile) == []: | 108 | if getValidMoves(mainBoard, playerTile) == []: |
| 97 | # If it's the player's turn but they | 109 | # If it's the player's turn but they |
| 98 | # can't move, then end the game. | 110 | # can't move, then end the game. |
| 99 | break | 111 | break |
| 100 | movexy = None | 112 | movexy = None |
| 101 | while movexy == None: | 113 | while movexy == None: |
| 102 | # Keep looping until the player clicks on a valid space. | 114 | # Keep looping until the player clicks on a valid space. |
| 103 | | 115 | |
| 104 | # Determine which board data structure to use for display. | 116 | # Determine which board data structure to use for display. |
| 105 | if showHints: | 117 | if showHints: |
| 106 | boardToDraw = getBoardWithValidMoves(mainBoard, playerTile) | 118 | boardToDraw = getBoardWithValidMoves(mainBoard, playerTile) |
| 107 | else: | 119 | else: |
| 108 | boardToDraw = mainBoard | 120 | boardToDraw = mainBoard |
| 109 | | 121 | |
| 110 | checkForQuit() | 122 | checkForQuit() |
| 111 | for event in pygame.event.get(): # event handling loop | 123 | for event in pygame.event.get(): # event handling loop |
| 112 | if event.type == MOUSEBUTTONUP: | 124 | if event.type == MOUSEBUTTONUP: |
| 113 | # Handle mouse click events | 125 | # Handle mouse click events |
| 114 | mousex, mousey = event.pos | 126 | mousex, mousey = event.pos |
| 115 | if newGameRect.collidepoint( (mousex, mousey) ): | 127 | if newGameRect.collidepoint( (mousex, mousey) ): |
| 116 | # Start a new game | 128 | # Start a new game |
| 117 | return True | 129 | return True |
| 118 | elif hintsRect.collidepoint( (mousex, mousey) ): | 130 | elif hintsRect.collidepoint( (mousex, mousey) ): |
| 119 | # Toggle hints mode | 131 | # Toggle hints mode |
| 120 | showHints = not showHints | 132 | showHints = not showHints |
| | | 133 | |
| | | 134 | # NEW SAVE FEATURE CODE: |
| | | 135 | elif saveButtonRect.collidepoint( (mousex, mousey) ): |
| | | 136 | # save the current game |
| | | 137 | saveGameShelfFile = shelve.open('flippySavedGames') |
| | | 138 | saveGameShelfFile['mainBoardVariable'] = mainBoard |
| | | 139 | saveGameShelfFile['playerTileVariable'] = playerTile |
| | | 140 | saveGameShelfFile['computerTileVariable'] = computerTile |
| | | 141 | saveGameShelfFile['turnVariable'] = turn |
| | | 142 | saveGameShelfFile['showHintsVariable'] = showHints |
| | | 143 | saveGameShelfFile.close() |
| | | 144 | |
| | | 145 | messageSurf = BIGFONT.render('Game Saved', True, TEXTCOLOR, TEXTBGCOLOR2) |
| | | 146 | messageRect = messageSurf.get_rect() |
| | | 147 | messageRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) |
| | | 148 | DISPLAYSURF.blit(messageSurf, messageRect) |
| | | 149 | pygame.display.update() |
| | | 150 | time.sleep(1) |
| | | 151 | |
| | | 152 | elif loadButtonRect.collidepoint( (mousex, mousey) ): |
| | | 153 | # load the previously saved game |
| | | 154 | saveGameShelfFile = shelve.open('flippySavedGames') |
| | | 155 | if 'mainBoardVariable' in saveGameShelfFile: |
| | | 156 | mainBoard = saveGameShelfFile['mainBoardVariable'] |
| | | 157 | playerTile = saveGameShelfFile['playerTileVariable'] |
| | | 158 | computerTile = saveGameShelfFile['computerTileVariable'] |
| | | 159 | turn = saveGameShelfFile['turnVariable'] |
| | | 160 | showHints = saveGameShelfFile['showHintsVariable'] |
| | | 161 | |
| | | 162 | messageSurf = BIGFONT.render('Game Loaded', True, TEXTCOLOR, TEXTBGCOLOR2) |
| | | 163 | messageRect = messageSurf.get_rect() |
| | | 164 | messageRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) |
| | | 165 | DISPLAYSURF.blit(messageSurf, messageRect) |
| | | 166 | pygame.display.update() |
| | | 167 | time.sleep(1) |
| | | 168 | |
| 121 | # movexy is set to a two-item tuple XY coordinate, or None value | 169 | # movexy is set to a two-item tuple XY coordinate, or None value |
| 122 | movexy = getSpaceClicked(mousex, mousey) | 170 | movexy = getSpaceClicked(mousex, mousey) |
| 123 | if movexy != None and not isValidMove(mainBoard, playerTile, movexy[0], movexy[1]): | 171 | if movexy != None and not isValidMove(mainBoard, playerTile, movexy[0], movexy[1]): |
| 124 | movexy = None | 172 | movexy = None |
| 125 | | 173 | |
| 126 | # Draw the game board. | 174 | # Draw the game board. |
| 127 | drawBoard(boardToDraw) | 175 | drawBoard(boardToDraw) |
| 128 | drawInfo(boardToDraw, playerTile, computerTile, turn) | 176 | drawInfo(boardToDraw, playerTile, computerTile, turn) |
| 129 | | 177 | |
| 130 | # Draw the "New Game" and "Hints" buttons. | 178 | # Draw the "New Game" and "Hints" buttons. |
| 131 | DISPLAYSURF.blit(newGameSurf, newGameRect) | 179 | DISPLAYSURF.blit(newGameSurf, newGameRect) |
| 132 | DISPLAYSURF.blit(hintsSurf, hintsRect) | 180 | DISPLAYSURF.blit(hintsSurf, hintsRect) |
| 133 | | 181 | |
| | | 182 | # NEW SAVE FEATURE CODE: |
| | | 183 | # Draw the "Save Game" and "Load Game" buttons. |
| | | 184 | DISPLAYSURF.blit(saveButtonSurf, saveButtonRect) |
| | | 185 | DISPLAYSURF.blit(loadButtonSurf, loadButtonRect) |
| | | 186 | |
| 134 | MAINCLOCK.tick(FPS) | 187 | MAINCLOCK.tick(FPS) |
| 135 | pygame.display.update() | 188 | pygame.display.update() |
| 136 | | 189 | |
| 137 | # Make the move and end the turn. | 190 | # Make the move and end the turn. |
| 138 | makeMove(mainBoard, playerTile, movexy[0], movexy[1], True) | 191 | makeMove(mainBoard, playerTile, movexy[0], movexy[1], True) |
| 139 | if getValidMoves(mainBoard, computerTile) != []: | 192 | if getValidMoves(mainBoard, computerTile) != []: |
| 140 | # Only set for the computer's turn if it can make a move. | 193 | # Only set for the computer's turn if it can make a move. |
| 141 | turn = 'computer' | 194 | turn = 'computer' |
| 142 | | 195 | |
| 143 | else: | 196 | else: |
| 144 | # Computer's turn: | 197 | # Computer's turn: |
| 145 | if getValidMoves(mainBoard, computerTile) == []: | 198 | if getValidMoves(mainBoard, computerTile) == []: |
| 146 | # If it was set to be the computer's turn but | 199 | # If it was set to be the computer's turn but |
| 147 | # they can't move, then end the game. | 200 | # they can't move, then end the game. |
| 148 | break | 201 | break |
| 149 | | 202 | |
| 150 | # Draw the board. | 203 | # Draw the board. |
| 151 | drawBoard(mainBoard) | 204 | drawBoard(mainBoard) |
| 152 | drawInfo(mainBoard, playerTile, computerTile, turn) | 205 | drawInfo(mainBoard, playerTile, computerTile, turn) |
| 153 | | 206 | |
| 154 | # Draw the "New Game" and "Hints" buttons. | 207 | # Draw the "New Game" and "Hints" buttons. |
| 155 | DISPLAYSURF.blit(newGameSurf, newGameRect) | 208 | DISPLAYSURF.blit(newGameSurf, newGameRect) |
| 156 | DISPLAYSURF.blit(hintsSurf, hintsRect) | 209 | DISPLAYSURF.blit(hintsSurf, hintsRect) |
| | | 210 | |
| | | 211 | # NEW SAVE FEATURE CODE: |
| | | 212 | # Draw the "Save Game" and "Load Game" buttons. |
| | | 213 | DISPLAYSURF.blit(saveButtonSurf, saveButtonRect) |
| | | 214 | DISPLAYSURF.blit(loadButtonSurf, loadButtonRect) |
| 157 | | 215 | |
| 158 | # Make it look like the computer is thinking by pausing a bit. | 216 | # Make it look like the computer is thinking by pausing a bit. |
| 159 | pauseUntil = time.time() + random.randint(5, 15) * 0.1 | 217 | pauseUntil = time.time() + random.randint(5, 15) * 0.1 |
| 160 | while time.time() < pauseUntil: | 218 | while time.time() < pauseUntil: |
| 161 | pygame.display.update() | 219 | pygame.display.update() |
| 162 | | 220 | |
| 163 | # Make the move and end the turn. | 221 | # Make the move and end the turn. |
| 164 | x, y = getComputerMove(mainBoard, computerTile) | 222 | x, y = getComputerMove(mainBoard, computerTile) |
| 165 | makeMove(mainBoard, computerTile, x, y, True) | 223 | makeMove(mainBoard, computerTile, x, y, True) |
| 166 | if getValidMoves(mainBoard, playerTile) != []: | 224 | if getValidMoves(mainBoard, playerTile) != []: |
| 167 | # Only set for the player's turn if they can make a move. | 225 | # Only set for the player's turn if they can make a move. |
| 168 | turn = 'player' | 226 | turn = 'player' |
| 169 | | 227 | |
| 170 | # Display the final score. | 228 | # Display the final score. |
| 171 | drawBoard(mainBoard) | 229 | drawBoard(mainBoard) |
| 172 | scores = getScoreOfBoard(mainBoard) | 230 | scores = getScoreOfBoard(mainBoard) |
| 173 | | 231 | |
| 174 | # Determine the text of the message to display. | 232 | # Determine the text of the message to display. |
| 175 | if scores[playerTile] > scores[computerTile]: | 233 | if scores[playerTile] > scores[computerTile]: |
| 176 | text = 'You beat the computer by %s points! Congratulations!' % \ | 234 | text = 'You beat the computer by %s points! Congratulations!' % \ |
| 177 | (scores[playerTile] - scores[computerTile]) | 235 | (scores[playerTile] - scores[computerTile]) |
| 178 | elif scores[playerTile] < scores[computerTile]: | 236 | elif scores[playerTile] < scores[computerTile]: |
| 179 | text = 'You lost. The computer beat you by %s points.' % \ | 237 | text = 'You lost. The computer beat you by %s points.' % \ |
| 180 | (scores[computerTile] - scores[playerTile]) | 238 | (scores[computerTile] - scores[playerTile]) |
| 181 | else: | 239 | else: |
| 182 | text = 'The game was a tie!' | 240 | text = 'The game was a tie!' |
| 183 | | 241 | |
| 184 | textSurf = FONT.render(text, True, TEXTCOLOR, TEXTBGCOLOR1) | 242 | textSurf = FONT.render(text, True, TEXTCOLOR, TEXTBGCOLOR1) |
| 185 | textRect = textSurf.get_rect() | 243 | textRect = textSurf.get_rect() |
| 186 | textRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) | 244 | textRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) |
| 187 | DISPLAYSURF.blit(textSurf, textRect) | 245 | DISPLAYSURF.blit(textSurf, textRect) |
| 188 | | 246 | |
| 189 | # Display the "Play again?" text with Yes and No buttons. | 247 | # Display the "Play again?" text with Yes and No buttons. |
| 190 | text2Surf = BIGFONT.render('Play again?', True, TEXTCOLOR, TEXTBGCOLOR1) | 248 | text2Surf = BIGFONT.render('Play again?', True, TEXTCOLOR, TEXTBGCOLOR1) |
| 191 | text2Rect = text2Surf.get_rect() | 249 | text2Rect = text2Surf.get_rect() |
| 192 | text2Rect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 50) | 250 | text2Rect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 50) |
| 193 | | 251 | |
| 194 | # Make "Yes" button. | 252 | # Make "Yes" button. |
| 195 | yesSurf = BIGFONT.render('Yes', True, TEXTCOLOR, TEXTBGCOLOR1) | 253 | yesSurf = BIGFONT.render('Yes', True, TEXTCOLOR, TEXTBGCOLOR1) |
| 196 | yesRect = yesSurf.get_rect() | 254 | yesRect = yesSurf.get_rect() |
| 197 | yesRect.center = (int(WINDOWWIDTH / 2) - 60, int(WINDOWHEIGHT / 2) + 90) | 255 | yesRect.center = (int(WINDOWWIDTH / 2) - 60, int(WINDOWHEIGHT / 2) + 90) |
| 198 | | 256 | |
| 199 | # Make "No" button. | 257 | # Make "No" button. |
| 200 | noSurf = BIGFONT.render('No', True, TEXTCOLOR, TEXTBGCOLOR1) | 258 | noSurf = BIGFONT.render('No', True, TEXTCOLOR, TEXTBGCOLOR1) |
| 201 | noRect = noSurf.get_rect() | 259 | noRect = noSurf.get_rect() |
| 202 | noRect.center = (int(WINDOWWIDTH / 2) + 60, int(WINDOWHEIGHT / 2) + 90) | 260 | noRect.center = (int(WINDOWWIDTH / 2) + 60, int(WINDOWHEIGHT / 2) + 90) |
| 203 | | 261 | |
| 204 | while True: | 262 | while True: |
| 205 | # Process events until the user clicks on Yes or No. | 263 | # Process events until the user clicks on Yes or No. |
| 206 | checkForQuit() | 264 | checkForQuit() |
| 207 | for event in pygame.event.get(): # event handling loop | 265 | for event in pygame.event.get(): # event handling loop |
| 208 | if event.type == MOUSEBUTTONUP: | 266 | if event.type == MOUSEBUTTONUP: |
| 209 | mousex, mousey = event.pos | 267 | mousex, mousey = event.pos |
| 210 | if yesRect.collidepoint( (mousex, mousey) ): | 268 | if yesRect.collidepoint( (mousex, mousey) ): |
| 211 | return True | 269 | return True |
| 212 | elif noRect.collidepoint( (mousex, mousey) ): | 270 | elif noRect.collidepoint( (mousex, mousey) ): |
| 213 | return False | 271 | return False |
| 214 | DISPLAYSURF.blit(textSurf, textRect) | 272 | DISPLAYSURF.blit(textSurf, textRect) |
| 215 | DISPLAYSURF.blit(text2Surf, text2Rect) | 273 | DISPLAYSURF.blit(text2Surf, text2Rect) |
| 216 | DISPLAYSURF.blit(yesSurf, yesRect) | 274 | DISPLAYSURF.blit(yesSurf, yesRect) |
| 217 | DISPLAYSURF.blit(noSurf, noRect) | 275 | DISPLAYSURF.blit(noSurf, noRect) |
| 218 | pygame.display.update() | 276 | pygame.display.update() |
| 219 | MAINCLOCK.tick(FPS) | 277 | MAINCLOCK.tick(FPS) |
| 220 | | 278 | |
| 221 | | 279 | |
| 222 | def translateBoardToPixelCoord(x, y): | 280 | def translateBoardToPixelCoord(x, y): |
| 223 | return XMARGIN + x * SPACESIZE + int(SPACESIZE / 2), YMARGIN + y * SPACESIZE + int(SPACESIZE / 2) | 281 | return XMARGIN + x * SPACESIZE + int(SPACESIZE / 2), YMARGIN + y * SPACESIZE + int(SPACESIZE / 2) |
| 224 | | 282 | |
| 225 | | 283 | |
| 226 | def animateTileChange(tilesToFlip, tileColor, additionalTile): | 284 | def animateTileChange(tilesToFlip, tileColor, additionalTile): |
| 227 | # Draw the additional tile that was just laid down. (Otherwise we'd | 285 | # Draw the additional tile that was just laid down. (Otherwise we'd |
| 228 | # have to completely redraw the board & the board info.) | 286 | # have to completely redraw the board & the board info.) |
| 229 | if tileColor == WHITE_TILE: | 287 | if tileColor == WHITE_TILE: |
| 230 | additionalTileColor = WHITE | 288 | additionalTileColor = WHITE |
| 231 | else: | 289 | else: |
| 232 | additionalTileColor = BLACK | 290 | additionalTileColor = BLACK |
| 233 | additionalTileX, additionalTileY = translateBoardToPixelCoord(additionalTile[0], additionalTile[1]) | 291 | additionalTileX, additionalTileY = translateBoardToPixelCoord(additionalTile[0], additionalTile[1]) |
| 234 | pygame.draw.circle(DISPLAYSURF, additionalTileColor, (additionalTileX, additionalTileY), int(SPACESIZE / 2) - 4) | 292 | pygame.draw.circle(DISPLAYSURF, additionalTileColor, (additionalTileX, additionalTileY), int(SPACESIZE / 2) - 4) |
| 235 | pygame.display.update() | 293 | pygame.display.update() |
| 236 | | 294 | |
| 237 | for rgbValues in range(0, 255, int(ANIMATIONSPEED * 2.55)): | 295 | for rgbValues in range(0, 255, int(ANIMATIONSPEED * 2.55)): |
| 238 | if rgbValues > 255: | 296 | if rgbValues > 255: |
| 239 | rgbValues = 255 | 297 | rgbValues = 255 |
| 240 | elif rgbValues < 0: | 298 | elif rgbValues < 0: |
| 241 | rgbValues = 0 | 299 | rgbValues = 0 |
| 242 | | 300 | |
| 243 | if tileColor == WHITE_TILE: | 301 | if tileColor == WHITE_TILE: |
| 244 | color = tuple([rgbValues] * 3) # rgbValues goes from 0 to 255 | 302 | color = tuple([rgbValues] * 3) # rgbValues goes from 0 to 255 |
| 245 | elif tileColor == BLACK_TILE: | 303 | elif tileColor == BLACK_TILE: |
| 246 | color = tuple([255 - rgbValues] * 3) # rgbValues goes from 255 to 0 | 304 | color = tuple([255 - rgbValues] * 3) # rgbValues goes from 255 to 0 |
| 247 | | 305 | |
| 248 | for x, y in tilesToFlip: | 306 | for x, y in tilesToFlip: |
| 249 | centerx, centery = translateBoardToPixelCoord(x, y) | 307 | centerx, centery = translateBoardToPixelCoord(x, y) |
| 250 | pygame.draw.circle(DISPLAYSURF, color, (centerx, centery), int(SPACESIZE / 2) - 4) | 308 | pygame.draw.circle(DISPLAYSURF, color, (centerx, centery), int(SPACESIZE / 2) - 4) |
| 251 | pygame.display.update() | 309 | pygame.display.update() |
| 252 | MAINCLOCK.tick(FPS) | 310 | MAINCLOCK.tick(FPS) |
| 253 | checkForQuit() | 311 | checkForQuit() |
| 254 | | 312 | |
| 255 | | 313 | |
| 256 | def drawBoard(board): | 314 | def drawBoard(board): |
| 257 | # Draw background of board. | 315 | # Draw background of board. |
| 258 | DISPLAYSURF.blit(BGIMAGE, BGIMAGE.get_rect()) | 316 | DISPLAYSURF.blit(BGIMAGE, BGIMAGE.get_rect()) |
| 259 | | 317 | |
| 260 | # Draw grid lines of the board. | 318 | # Draw grid lines of the board. |
| 261 | for x in range(BOARDWIDTH + 1): | 319 | for x in range(BOARDWIDTH + 1): |
| 262 | # Draw the horizontal lines. | 320 | # Draw the horizontal lines. |
| 263 | startx = (x * SPACESIZE) + XMARGIN | 321 | startx = (x * SPACESIZE) + XMARGIN |
| 264 | starty = YMARGIN | 322 | starty = YMARGIN |
| 265 | endx = (x * SPACESIZE) + XMARGIN | 323 | endx = (x * SPACESIZE) + XMARGIN |
| 266 | endy = YMARGIN + (BOARDHEIGHT * SPACESIZE) | 324 | endy = YMARGIN + (BOARDHEIGHT * SPACESIZE) |
| 267 | pygame.draw.line(DISPLAYSURF, GRIDLINECOLOR, (startx, starty), (endx, endy)) | 325 | pygame.draw.line(DISPLAYSURF, GRIDLINECOLOR, (startx, starty), (endx, endy)) |
| 268 | for y in range(BOARDHEIGHT + 1): | 326 | for y in range(BOARDHEIGHT + 1): |
| 269 | # Draw the vertical lines. | 327 | # Draw the vertical lines. |
| 270 | startx = XMARGIN | 328 | startx = XMARGIN |
| 271 | starty = (y * SPACESIZE) + YMARGIN | 329 | starty = (y * SPACESIZE) + YMARGIN |
| 272 | endx = XMARGIN + (BOARDWIDTH * SPACESIZE) | 330 | endx = XMARGIN + (BOARDWIDTH * SPACESIZE) |
| 273 | endy = (y * SPACESIZE) + YMARGIN | 331 | endy = (y * SPACESIZE) + YMARGIN |
| 274 | pygame.draw.line(DISPLAYSURF, GRIDLINECOLOR, (startx, starty), (endx, endy)) | 332 | pygame.draw.line(DISPLAYSURF, GRIDLINECOLOR, (startx, starty), (endx, endy)) |
| 275 | | 333 | |
| 276 | # Draw the black & white tiles or hint spots. | 334 | # Draw the black & white tiles or hint spots. |
| 277 | for x in range(BOARDWIDTH): | 335 | for x in range(BOARDWIDTH): |
| 278 | for y in range(BOARDHEIGHT): | 336 | for y in range(BOARDHEIGHT): |
| 279 | centerx, centery = translateBoardToPixelCoord(x, y) | 337 | centerx, centery = translateBoardToPixelCoord(x, y) |
| 280 | if board[x][y] == WHITE_TILE or board[x][y] == BLACK_TILE: | 338 | if board[x][y] == WHITE_TILE or board[x][y] == BLACK_TILE: |
| 281 | if board[x][y] == WHITE_TILE: | 339 | if board[x][y] == WHITE_TILE: |
| 282 | tileColor = WHITE | 340 | tileColor = WHITE |
| 283 | else: | 341 | else: |
| 284 | tileColor = BLACK | 342 | tileColor = BLACK |
| 285 | pygame.draw.circle(DISPLAYSURF, tileColor, (centerx, centery), int(SPACESIZE / 2) - 4) | 343 | pygame.draw.circle(DISPLAYSURF, tileColor, (centerx, centery), int(SPACESIZE / 2) - 4) |
| 286 | if board[x][y] == HINT_TILE: | 344 | if board[x][y] == HINT_TILE: |
| 287 | pygame.draw.rect(DISPLAYSURF, HINTCOLOR, (centerx - 4, centery - 4, 8, 8)) | 345 | pygame.draw.rect(DISPLAYSURF, HINTCOLOR, (centerx - 4, centery - 4, 8, 8)) |
| 288 | | 346 | |
| 289 | | 347 | |
| 290 | def getSpaceClicked(mousex, mousey): | 348 | def getSpaceClicked(mousex, mousey): |
| 291 | # Return a tuple of two integers of the board space coordinates where | 349 | # Return a tuple of two integers of the board space coordinates where |
| 292 | # the mouse was clicked. (Or returns None not in any space.) | 350 | # the mouse was clicked. (Or returns None not in any space.) |
| 293 | for x in range(BOARDWIDTH): | 351 | for x in range(BOARDWIDTH): |
| 294 | for y in range(BOARDHEIGHT): | 352 | for y in range(BOARDHEIGHT): |
| 295 | if mousex > x * SPACESIZE + XMARGIN and \ | 353 | if mousex > x * SPACESIZE + XMARGIN and \ |
| 296 | mousex < (x + 1) * SPACESIZE + XMARGIN and \ | 354 | mousex < (x + 1) * SPACESIZE + XMARGIN and \ |
| 297 | mousey > y * SPACESIZE + YMARGIN and \ | 355 | mousey > y * SPACESIZE + YMARGIN and \ |
| 298 | mousey < (y + 1) * SPACESIZE + YMARGIN: | 356 | mousey < (y + 1) * SPACESIZE + YMARGIN: |
| 299 | return (x, y) | 357 | return (x, y) |
| 300 | return None | 358 | return None |
| 301 | | 359 | |
| 302 | | 360 | |
| 303 | def drawInfo(board, playerTile, computerTile, turn): | 361 | def drawInfo(board, playerTile, computerTile, turn): |
| 304 | # Draws scores and whose turn it is at the bottom of the screen. | 362 | # Draws scores and whose turn it is at the bottom of the screen. |
| 305 | scores = getScoreOfBoard(board) | 363 | scores = getScoreOfBoard(board) |
| 306 | scoreSurf = FONT.render("Player Score: %s Computer Score: %s %s's Turn" % (str(scores[playerTile]), str(scores[computerTile]), turn.title()), True, TEXTCOLOR) | 364 | scoreSurf = FONT.render("Player Score: %s Computer Score: %s %s's Turn" % (str(scores[playerTile]), str(scores[computerTile]), turn.title()), True, TEXTCOLOR) |
| 307 | scoreRect = scoreSurf.get_rect() | 365 | scoreRect = scoreSurf.get_rect() |
| 308 | scoreRect.bottomleft = (10, WINDOWHEIGHT - 5) | 366 | scoreRect.bottomleft = (10, WINDOWHEIGHT - 5) |
| 309 | DISPLAYSURF.blit(scoreSurf, scoreRect) | 367 | DISPLAYSURF.blit(scoreSurf, scoreRect) |
| 310 | | 368 | |
| 311 | | 369 | |
| 312 | def resetBoard(board): | 370 | def resetBoard(board): |
| 313 | # Blanks out the board it is passed, and sets up starting tiles. | 371 | # Blanks out the board it is passed, and sets up starting tiles. |
| 314 | for x in range(BOARDWIDTH): | 372 | for x in range(BOARDWIDTH): |
| 315 | for y in range(BOARDHEIGHT): | 373 | for y in range(BOARDHEIGHT): |
| 316 | board[x][y] = EMPTY_SPACE | 374 | board[x][y] = EMPTY_SPACE |
| 317 | | 375 | |
| 318 | # Add starting pieces to the center | 376 | # Add starting pieces to the center |
| 319 | board[3][3] = WHITE_TILE | 377 | board[3][3] = WHITE_TILE |
| 320 | board[3][4] = BLACK_TILE | 378 | board[3][4] = BLACK_TILE |
| 321 | board[4][3] = BLACK_TILE | 379 | board[4][3] = BLACK_TILE |
| 322 | board[4][4] = WHITE_TILE | 380 | board[4][4] = WHITE_TILE |
| 323 | | 381 | |
| 324 | | 382 | |
| 325 | def getNewBoard(): | 383 | def getNewBoard(): |
| 326 | # Creates a brand new, empty board data structure. | 384 | # Creates a brand new, empty board data structure. |
| 327 | board = [] | 385 | board = [] |
| 328 | for i in range(BOARDWIDTH): | 386 | for i in range(BOARDWIDTH): |
| 329 | board.append([EMPTY_SPACE] * BOARDHEIGHT) | 387 | board.append([EMPTY_SPACE] * BOARDHEIGHT) |
| 330 | | 388 | |
| 331 | return board | 389 | return board |
| 332 | | 390 | |
| 333 | | 391 | |
| 334 | def isValidMove(board, tile, xstart, ystart): | 392 | def isValidMove(board, tile, xstart, ystart): |
| 335 | # Returns False if the player's move is invalid. If it is a valid | 393 | # Returns False if the player's move is invalid. If it is a valid |
| 336 | # move, returns a list of spaces of the captured pieces. | 394 | # move, returns a list of spaces of the captured pieces. |
| 337 | if board[xstart][ystart] != EMPTY_SPACE or not isOnBoard(xstart, ystart): | 395 | if board[xstart][ystart] != EMPTY_SPACE or not isOnBoard(xstart, ystart): |
| 338 | return False | 396 | return False |
| 339 | | 397 | |
| 340 | board[xstart][ystart] = tile # temporarily set the tile on the board. | 398 | board[xstart][ystart] = tile # temporarily set the tile on the board. |
| 341 | | 399 | |
| 342 | if tile == WHITE_TILE: | 400 | if tile == WHITE_TILE: |
| 343 | otherTile = BLACK_TILE | 401 | otherTile = BLACK_TILE |
| 344 | else: | 402 | else: |
| 345 | otherTile = WHITE_TILE | 403 | otherTile = WHITE_TILE |
| 346 | | 404 | |
| 347 | tilesToFlip = [] | 405 | tilesToFlip = [] |
| 348 | # check each of the eight directions: | 406 | # check each of the eight directions: |
| 349 | for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]: | 407 | for xdirection, ydirection in [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]: |
| 350 | x, y = xstart, ystart | 408 | x, y = xstart, ystart |
| 351 | x += xdirection | 409 | x += xdirection |
| 352 | y += ydirection | 410 | y += ydirection |
| 353 | if isOnBoard(x, y) and board[x][y] == otherTile: | 411 | if isOnBoard(x, y) and board[x][y] == otherTile: |
| 354 | # The piece belongs to the other player next to our piece. | 412 | # The piece belongs to the other player next to our piece. |
| 355 | x += xdirection | 413 | x += xdirection |
| 356 | y += ydirection | 414 | y += ydirection |
| 357 | if not isOnBoard(x, y): | 415 | if not isOnBoard(x, y): |
| 358 | continue | 416 | continue |
| 359 | while board[x][y] == otherTile: | 417 | while board[x][y] == otherTile: |
| 360 | x += xdirection | 418 | x += xdirection |
| 361 | y += ydirection | 419 | y += ydirection |
| 362 | if not isOnBoard(x, y): | 420 | if not isOnBoard(x, y): |
| 363 | break # break out of while loop, continue in for loop | 421 | break # break out of while loop, continue in for loop |
| 364 | if not isOnBoard(x, y): | 422 | if not isOnBoard(x, y): |
| 365 | continue | 423 | continue |
| 366 | if board[x][y] == tile: | 424 | if board[x][y] == tile: |
| 367 | # There are pieces to flip over. Go in the reverse | 425 | # There are pieces to flip over. Go in the reverse |
| 368 | # direction until we reach the original space, noting all | 426 | # direction until we reach the original space, noting all |
| 369 | # the tiles along the way. | 427 | # the tiles along the way. |
| 370 | while True: | 428 | while True: |
| 371 | x -= xdirection | 429 | x -= xdirection |
| 372 | y -= ydirection | 430 | y -= ydirection |
| 373 | if x == xstart and y == ystart: | 431 | if x == xstart and y == ystart: |
| 374 | break | 432 | break |
| 375 | tilesToFlip.append([x, y]) | 433 | tilesToFlip.append([x, y]) |
| 376 | | 434 | |
| 377 | board[xstart][ystart] = EMPTY_SPACE # make space empty | 435 | board[xstart][ystart] = EMPTY_SPACE # make space empty |
| 378 | if len(tilesToFlip) == 0: # If no tiles flipped, this move is invalid | 436 | if len(tilesToFlip) == 0: # If no tiles flipped, this move is invalid |
| 379 | return False | 437 | return False |
| 380 | return tilesToFlip | 438 | return tilesToFlip |
| 381 | | 439 | |
| 382 | | 440 | |
| 383 | def isOnBoard(x, y): | 441 | def isOnBoard(x, y): |
| 384 | # Returns True if the coordinates are located on the board. | 442 | # Returns True if the coordinates are located on the board. |
| 385 | return x >= 0 and x < BOARDWIDTH and y >= 0 and y < BOARDHEIGHT | 443 | return x >= 0 and x < BOARDWIDTH and y >= 0 and y < BOARDHEIGHT |
| 386 | | 444 | |
| 387 | | 445 | |
| 388 | def getBoardWithValidMoves(board, tile): | 446 | def getBoardWithValidMoves(board, tile): |
| 389 | # Returns a new board with hint markings. | 447 | # Returns a new board with hint markings. |
| 390 | dupeBoard = copy.deepcopy(board) | 448 | dupeBoard = copy.deepcopy(board) |
| 391 | | 449 | |
| 392 | for x, y in getValidMoves(dupeBoard, tile): | 450 | for x, y in getValidMoves(dupeBoard, tile): |
| 393 | dupeBoard[x][y] = HINT_TILE | 451 | dupeBoard[x][y] = HINT_TILE |
| 394 | return dupeBoard | 452 | return dupeBoard |
| 395 | | 453 | |
| 396 | | 454 | |
| 397 | def getValidMoves(board, tile): | 455 | def getValidMoves(board, tile): |
| 398 | # Returns a list of (x,y) tuples of all valid moves. | 456 | # Returns a list of (x,y) tuples of all valid moves. |
| 399 | validMoves = [] | 457 | validMoves = [] |
| 400 | | 458 | |
| 401 | for x in range(BOARDWIDTH): | 459 | for x in range(BOARDWIDTH): |
| 402 | for y in range(BOARDHEIGHT): | 460 | for y in range(BOARDHEIGHT): |
| 403 | if isValidMove(board, tile, x, y) != False: | 461 | if isValidMove(board, tile, x, y) != False: |
| 404 | validMoves.append((x, y)) | 462 | validMoves.append((x, y)) |
| 405 | return validMoves | 463 | return validMoves |
| 406 | | 464 | |
| 407 | | 465 | |
| 408 | def getScoreOfBoard(board): | 466 | def getScoreOfBoard(board): |
| 409 | # Determine the score by counting the tiles. | 467 | # Determine the score by counting the tiles. |
| 410 | xscore = 0 | 468 | xscore = 0 |
| 411 | oscore = 0 | 469 | oscore = 0 |
| 412 | for x in range(BOARDWIDTH): | 470 | for x in range(BOARDWIDTH): |
| 413 | for y in range(BOARDHEIGHT): | 471 | for y in range(BOARDHEIGHT): |
| 414 | if board[x][y] == WHITE_TILE: | 472 | if board[x][y] == WHITE_TILE: |
| 415 | xscore += 1 | 473 | xscore += 1 |
| 416 | if board[x][y] == BLACK_TILE: | 474 | if board[x][y] == BLACK_TILE: |
| 417 | oscore += 1 | 475 | oscore += 1 |
| 418 | return {WHITE_TILE:xscore, BLACK_TILE:oscore} | 476 | return {WHITE_TILE:xscore, BLACK_TILE:oscore} |
| 419 | | 477 | |
| 420 | | 478 | |
| 421 | def enterPlayerTile(): | 479 | def enterPlayerTile(): |
| 422 | # Draws the text and handles the mouse click events for letting | 480 | # Draws the text and handles the mouse click events for letting |
| 423 | # the player choose which color they want to be. Returns | 481 | # the player choose which color they want to be. Returns |
| 424 | # [WHITE_TILE, BLACK_TILE] if the player chooses to be White, | 482 | # [WHITE_TILE, BLACK_TILE] if the player chooses to be White, |
| 425 | # [BLACK_TILE, WHITE_TILE] if Black. | 483 | # [BLACK_TILE, WHITE_TILE] if Black. |
| 426 | | 484 | |
| 427 | # Create the text. | 485 | # Create the text. |
| 428 | textSurf = FONT.render('Do you want to be white or black?', True, TEXTCOLOR, TEXTBGCOLOR1) | 486 | textSurf = FONT.render('Do you want to be white or black?', True, TEXTCOLOR, TEXTBGCOLOR1) |
| 429 | textRect = textSurf.get_rect() | 487 | textRect = textSurf.get_rect() |
| 430 | textRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) | 488 | textRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2)) |
| 431 | | 489 | |
| 432 | xSurf = BIGFONT.render('White', True, TEXTCOLOR, TEXTBGCOLOR1) | 490 | xSurf = BIGFONT.render('White', True, TEXTCOLOR, TEXTBGCOLOR1) |
| 433 | xRect = xSurf.get_rect() | 491 | xRect = xSurf.get_rect() |
| 434 | xRect.center = (int(WINDOWWIDTH / 2) - 60, int(WINDOWHEIGHT / 2) + 40) | 492 | xRect.center = (int(WINDOWWIDTH / 2) - 60, int(WINDOWHEIGHT / 2) + 40) |
| 435 | | 493 | |
| 436 | oSurf = BIGFONT.render('Black', True, TEXTCOLOR, TEXTBGCOLOR1) | 494 | oSurf = BIGFONT.render('Black', True, TEXTCOLOR, TEXTBGCOLOR1) |
| 437 | oRect = oSurf.get_rect() | 495 | oRect = oSurf.get_rect() |
| 438 | oRect.center = (int(WINDOWWIDTH / 2) + 60, int(WINDOWHEIGHT / 2) + 40) | 496 | oRect.center = (int(WINDOWWIDTH / 2) + 60, int(WINDOWHEIGHT / 2) + 40) |
| 439 | | 497 | |
| 440 | while True: | 498 | while True: |
| 441 | # Keep looping until the player has clicked on a color. | 499 | # Keep looping until the player has clicked on a color. |
| 442 | checkForQuit() | 500 | checkForQuit() |
| 443 | for event in pygame.event.get(): # event handling loop | 501 | for event in pygame.event.get(): # event handling loop |
| 444 | if event.type == MOUSEBUTTONUP: | 502 | if event.type == MOUSEBUTTONUP: |
| 445 | mousex, mousey = event.pos | 503 | mousex, mousey = event.pos |
| 446 | if xRect.collidepoint( (mousex, mousey) ): | 504 | if xRect.collidepoint( (mousex, mousey) ): |
| 447 | return [WHITE_TILE, BLACK_TILE] | 505 | return [WHITE_TILE, BLACK_TILE] |
| 448 | elif oRect.collidepoint( (mousex, mousey) ): | 506 | elif oRect.collidepoint( (mousex, mousey) ): |
| 449 | return [BLACK_TILE, WHITE_TILE] | 507 | return [BLACK_TILE, WHITE_TILE] |
| 450 | | 508 | |
| 451 | # Draw the screen. | 509 | # Draw the screen. |
| 452 | DISPLAYSURF.blit(textSurf, textRect) | 510 | DISPLAYSURF.blit(textSurf, textRect) |
| 453 | DISPLAYSURF.blit(xSurf, xRect) | 511 | DISPLAYSURF.blit(xSurf, xRect) |
| 454 | DISPLAYSURF.blit(oSurf, oRect) | 512 | DISPLAYSURF.blit(oSurf, oRect) |
| 455 | pygame.display.update() | 513 | pygame.display.update() |
| 456 | MAINCLOCK.tick(FPS) | 514 | MAINCLOCK.tick(FPS) |
| 457 | | 515 | |
| 458 | | 516 | |
| 459 | def makeMove(board, tile, xstart, ystart, realMove=False): | 517 | def makeMove(board, tile, xstart, ystart, realMove=False): |
| 460 | # Place the tile on the board at xstart, ystart, and flip tiles | 518 | # Place the tile on the board at xstart, ystart, and flip tiles |
| 461 | # Returns False if this is an invalid move, True if it is valid. | 519 | # Returns False if this is an invalid move, True if it is valid. |
| 462 | tilesToFlip = isValidMove(board, tile, xstart, ystart) | 520 | tilesToFlip = isValidMove(board, tile, xstart, ystart) |
| 463 | | 521 | |
| 464 | if tilesToFlip == False: | 522 | if tilesToFlip == False: |
| 465 | return False | 523 | return False |
| 466 | | 524 | |
| 467 | board[xstart][ystart] = tile | 525 | board[xstart][ystart] = tile |
| 468 | | 526 | |
| 469 | if realMove: | 527 | if realMove: |
| 470 | animateTileChange(tilesToFlip, tile, (xstart, ystart)) | 528 | animateTileChange(tilesToFlip, tile, (xstart, ystart)) |
| 471 | | 529 | |
| 472 | for x, y in tilesToFlip: | 530 | for x, y in tilesToFlip: |
| 473 | board[x][y] = tile | 531 | board[x][y] = tile |
| 474 | return True | 532 | return True |
| 475 | | 533 | |
| 476 | | 534 | |
| 477 | def isOnCorner(x, y): | 535 | def isOnCorner(x, y): |
| 478 | # Returns True if the position is in one of the four corners. | 536 | # Returns True if the position is in one of the four corners. |
| 479 | return (x == 0 and y == 0) or \ | 537 | return (x == 0 and y == 0) or \ |
| 480 | (x == BOARDWIDTH and y == 0) or \ | 538 | (x == BOARDWIDTH and y == 0) or \ |
| 481 | (x == 0 and y == BOARDHEIGHT) or \ | 539 | (x == 0 and y == BOARDHEIGHT) or \ |
| 482 | (x == BOARDWIDTH and y == BOARDHEIGHT) | 540 | (x == BOARDWIDTH and y == BOARDHEIGHT) |
| 483 | | 541 | |
| 484 | | 542 | |
| 485 | def getComputerMove(board, computerTile): | 543 | def getComputerMove(board, computerTile): |
| 486 | # Given a board and the computer's tile, determine where to | 544 | # Given a board and the computer's tile, determine where to |
| 487 | # move and return that move as a [x, y] list. | 545 | # move and return that move as a [x, y] list. |
| 488 | possibleMoves = getValidMoves(board, computerTile) | 546 | possibleMoves = getValidMoves(board, computerTile) |
| 489 | | 547 | |
| 490 | # randomize the order of the possible moves | 548 | # randomize the order of the possible moves |
| 491 | random.shuffle(possibleMoves) | 549 | random.shuffle(possibleMoves) |
| 492 | | 550 | |
| 493 | # always go for a corner if available. | 551 | # always go for a corner if available. |
| 494 | for x, y in possibleMoves: | 552 | for x, y in possibleMoves: |
| 495 | if isOnCorner(x, y): | 553 | if isOnCorner(x, y): |
| 496 | return [x, y] | 554 | return [x, y] |
| 497 | | 555 | |
| 498 | # Go through all possible moves and remember the best scoring move | 556 | # Go through all possible moves and remember the best scoring move |
| 499 | bestScore = -1 | 557 | bestScore = -1 |
| 500 | for x, y in possibleMoves: | 558 | for x, y in possibleMoves: |
| 501 | dupeBoard = copy.deepcopy(board) | 559 | dupeBoard = copy.deepcopy(board) |
| 502 | makeMove(dupeBoard, computerTile, x, y) | 560 | makeMove(dupeBoard, computerTile, x, y) |
| 503 | score = getScoreOfBoard(dupeBoard)[computerTile] | 561 | score = getScoreOfBoard(dupeBoard)[computerTile] |
| 504 | if score > bestScore: | 562 | if score > bestScore: |
| 505 | bestMove = [x, y] | 563 | bestMove = [x, y] |
| 506 | bestScore = score | 564 | bestScore = score |
| 507 | return bestMove | 565 | return bestMove |
| 508 | | 566 | |
| 509 | | 567 | |
| 510 | def checkForQuit(): | 568 | def checkForQuit(): |
| 511 | for event in pygame.event.get((QUIT, KEYUP)): # event handling loop | 569 | for event in pygame.event.get((QUIT, KEYUP)): # event handling loop |
| 512 | if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE): | 570 | if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE): |
| 513 | pygame.quit() | 571 | pygame.quit() |
| 514 | sys.exit() | 572 | sys.exit() |
| 515 | | 573 | |
| 516 | | 574 | |
| 517 | if __name__ == '__main__': | 575 | if __name__ == '__main__': |
| 518 | main() | 576 | main() |