Advertisement
asweigart

OOP Tic Tac Toe

Jun 30th, 2019
272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.90 KB | None | 0 0
  1. # tictactoe_oop2.py, An object-oriented Tic Tac Toe game.
  2. # By Al Sweigart al@inventwithpython.com
  3.  
  4. # Setting up constants:
  5. ALL_SPACES = list('123456789') # The keys for a TTT board.
  6. X, O, BLANK = 'X', 'O', ' '
  7.  
  8. def main():
  9.     """Runs a game of Tic Tac Toe."""
  10.     print('Welcome to Tic Tac Toe!')
  11.     gameBoard = LoggingPrettyTTTBoard('#', 'tttlog.txt') # Create a TTT board object.
  12.     currentPlayer, nextPlayer = X, O # X goes first, O goes next.
  13.  
  14.     while True:
  15.         print(gameBoard.getBoardStr()) # Display the board on the screen.
  16.  
  17.         # Keep asking the player until they enter a number 1-9:
  18.         move = None
  19.         while move not in ALL_SPACES or gameBoard.spaces[move] != BLANK:
  20.             print(f'What is {currentPlayer}\'s move? (1-9)')
  21.             move = input()
  22.         gameBoard.updateBoard(move, currentPlayer) # Make the move.
  23.  
  24.         # Check if the game is over:
  25.         if gameBoard.isWinner(currentPlayer):
  26.             print(gameBoard.getBoardStr())
  27.             print(currentPlayer + ' has won the game!')
  28.             break
  29.         elif gameBoard.isBoardFull():
  30.             print(gameBoard.getBoardStr())
  31.             print('The game is a tie!')
  32.             break
  33.         currentPlayer, nextPlayer = nextPlayer, currentPlayer # Swap turns.
  34.  
  35. class TTTBoard:
  36.     def __init__(self, usePrettyBoard=False, useLogging=False):
  37.         """Create a new, blank tic tac toe board."""
  38.         self.spaces = {} # The board is represented as a Python dictionary.
  39.         for space in ALL_SPACES:
  40.             self.spaces[space] = BLANK # All spaces start as blank.
  41.  
  42.     def getBoardStr(self):
  43.         """Return  a text-representation of the board."""
  44.         return f'''
  45.      {self.spaces['1']}|{self.spaces['2']}|{self.spaces['3']}  1 2 3
  46.      -+-+-
  47.      {self.spaces['4']}|{self.spaces['5']}|{self.spaces['6']}  4 5 6
  48.      -+-+-
  49.      {self.spaces['7']}|{self.spaces['8']}|{self.spaces['9']}  7 8 9'''
  50.  
  51.     def isWinner(self, player):
  52.         """Return True if player is a winner on this TTTBoard."""
  53.         b, p = self.spaces, player # Shorter names as "syntactic sugar".
  54.         # Check for 3 marks across the 3 rows, 3 columns, and 2 diagonals.
  55.         return ((b['1'] == b['2'] == b['3'] == p) or # Across the top
  56.                 (b['4'] == b['5'] == b['6'] == p) or # Across the middle
  57.                 (b['7'] == b['8'] == b['9'] == p) or # Across the bottom
  58.                 (b['1'] == b['4'] == b['7'] == p) or # Down the left
  59.                 (b['2'] == b['5'] == b['8'] == p) or # Down the middle
  60.                 (b['3'] == b['6'] == b['9'] == p) or # Down the right
  61.                 (b['3'] == b['5'] == b['7'] == p) or # Diagonal
  62.                 (b['1'] == b['5'] == b['9'] == p))   # Diagonal
  63.  
  64.     def isBoardFull(self):
  65.         """Return True if every space on the board has been taken."""
  66.         for space in ALL_SPACES:
  67.             if self.spaces[space] == BLANK:
  68.                 return False # If a single space is blank, return False.
  69.         return True # No spaces are blank, so return True.
  70.  
  71.     def updateBoard(self, space, player):
  72.         """Sets the space on the board to player."""
  73.         self.spaces[space] = player
  74.  
  75.  
  76. class PrettyTTTBoard(TTTBoard):
  77.     def __init__(self, crossChar):
  78.         super().__init__()
  79.         self.crossChar = crossChar
  80.  
  81.     def getBoardStr(self):
  82.         canvas = {}
  83.         # Draw the board lines:
  84.         for i in range(17):
  85.             canvas[(5, i)] = self.crossChar
  86.             canvas[(11, i)] = self.crossChar
  87.             canvas[(i, 5)] = self.crossChar
  88.             canvas[(i, 11)] = self.crossChar
  89.  
  90.         # Draw the Xs and Os or space numbers:
  91.         i = 0
  92.         for y in (0, 6, 12):
  93.             for x in (0, 6, 12):
  94.                 i += 1
  95.                 if self.spaces[str(i)] == X:
  96.                     # Draw an X:
  97.                     canvas[(1 + x, 1 + y)] = X
  98.                     canvas[(3 + x, 1 + y)] = X
  99.                     canvas[(2 + x, 2 + y)] = X
  100.                     canvas[(1 + x, 3 + y)] = X
  101.                     canvas[(3 + x, 3 + y)] = X
  102.                 elif self.spaces[str(i)] == O:
  103.                     # Draw an O:
  104.                     canvas[(1 + x, 1 + y)] = O
  105.                     canvas[(2 + x, 1 + y)] = O
  106.                     canvas[(3 + x, 1 + y)] = O
  107.                     canvas[(1 + x, 2 + y)] = O
  108.                     canvas[(3 + x, 2 + y)] = O
  109.                     canvas[(1 + x, 3 + y)] = O
  110.                     canvas[(2 + x, 3 + y)] = O
  111.                     canvas[(3 + x, 3 + y)] = O
  112.                 else:
  113.                     # Draw the space number label:
  114.                     canvas[(2 + x, 2 + y)] = str(i)
  115.  
  116.         # Print the canvas on the screen:
  117.         boardStrAsList = [] # Print a blank line as a spacer.
  118.         for y in range(17):
  119.             for x in range(17):
  120.                 if (x, y) in canvas:
  121.                     boardStrAsList.append(canvas[(x, y)])
  122.                 else:
  123.                     boardStrAsList.append(' ')
  124.             boardStrAsList.append('\n')
  125.         return ''.join(boardStrAsList)
  126.  
  127.  
  128. class LoggingTTTBoard(TTTBoard):
  129.     def __init__(self, logFilename):
  130.         """Create a new, blank tic tac toe board."""
  131.         super().__init__()
  132.         self.logFilename = logFilename
  133.  
  134.     def updateBoard(self, space, player):
  135.         """Sets the space on the board to player, but also records each move
  136.        to the log file."""
  137.         super().updateBoard(space, player)
  138.         with open(self.logFilename, 'a') as logFile:
  139.             logFile.write(f'{player} moved on space {space}:\n')
  140.             logFile.write(super().getBoardStr() + '\n')
  141.  
  142.  
  143. class LoggingPrettyTTTBoard(LoggingTTTBoard, PrettyTTTBoard):
  144.     def __init__(self, crossChar, logFilename):
  145.         self.logFilename = logFilename
  146.         PrettyTTTBoard.__init__(self, crossChar)
  147.  
  148.  
  149. if __name__ == '__main__':
  150.     main() # Call main() if this module is run, but not when imported.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement