Indie_Coder

Tictactoe Board Module

Jun 18th, 2022 (edited)
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.10 KB | None | 0 0
  1. from typing import Optional
  2.  
  3. class Board:
  4.     P1 = 'O'
  5.     P2 = 'X'
  6.     EMPTY = '#'
  7.  
  8.     def __init__(self, size: int = 3) -> None:
  9.         self.size = size
  10.         self.first_move = None
  11.         self.turn = None
  12.         self.table = None
  13.         self.p1_score = 0
  14.         self.p2_score = 0
  15.  
  16.         self.SQUARES = self._squares()
  17.         self.ROWS, self.COLS = self._rows_cols()
  18.         self.DIAS = self._diagonals()
  19.         self.WIN_CONDITIONS = self.ROWS + self.COLS + self.DIAS
  20.         self.reset()
  21.  
  22.     def _squares(self) -> dict:
  23.         """Dictionary containing square name
  24.        for each row, column in table
  25.        """
  26.         return {(r, c): r*self.size+c for r in range(self.size) for c in range(self.size)}
  27.  
  28.     def _new_table(self) -> list:
  29.         """Empty list for storing player's value
  30.        """
  31.         return [self.EMPTY for _ in range(self.size**2)]
  32.  
  33.     def _rows_cols(self) -> tuple[list, list]:
  34.         """Return lists of rows and columns
  35.        """
  36.         rows: list[list] = [[] for _ in range(self.size)]
  37.         columns: list[list] = [[] for _ in range(self.size)]
  38.         for index, square in self.SQUARES.items():
  39.             r, c = index
  40.             rows[r].append(square)
  41.             columns[c].append(square)
  42.         return rows, columns
  43.  
  44.     def _diagonals(self) -> list:
  45.         """Return lists of diagonals
  46.        """
  47.         diagonals: list[list] = [[], []]
  48.         i = 0
  49.         j = self.size-1
  50.         for _ in range(self.size):
  51.             diagonals[0].append(i)
  52.             diagonals[1].append(j)
  53.             i += self.size + 1
  54.             j += self.size - 1
  55.         return diagonals
  56.  
  57.     @property
  58.     def empty_squares(self) -> list[int]:
  59.         """Return the list of indices of empty squares
  60.        """
  61.         return [square for square in self.SQUARES.values() if self.is_empty(square)]
  62.  
  63.     def reset(self) -> None:
  64.         """Set the board to starting position
  65.        for the next game
  66.        """
  67.         self.table = self._new_table()
  68.         self.first_move = self.P2 if self.first_move == self.P1 else self.P1
  69.         self.turn = self.first_move
  70.  
  71.     def square_pos(self, square: int) -> Optional[tuple]:
  72.         """Return the row, col according to
  73.        the index of the square in board's table
  74.        """
  75.         for index, sq in self.SQUARES.items():
  76.             if sq == square:
  77.                 return index
  78.         return None
  79.  
  80.     def square_name(self, row: int, col: int) -> int:
  81.         """Return the index of the square in the
  82.        board's table
  83.        """
  84.         return self.SQUARES[(row, col)]
  85.  
  86.     def square_value(self, square: int) -> str:
  87.         """Return the value stored in square's index
  88.        """
  89.         return self.table[square]
  90.  
  91.     def is_empty(self, square: int) -> bool:
  92.         """Check if the square is occupied
  93.        """
  94.         return self.table[square] == self.EMPTY
  95.  
  96.     def get_connection(self) -> list[int]:
  97.         """Return the connected player if exists
  98.        """
  99.         for row in self.WIN_CONDITIONS:
  100.             checklist = []
  101.             for square in row:
  102.                 if self.is_empty(square):
  103.                     continue
  104.                 checklist.append(self.square_value(square))
  105.             if len(checklist) == self.size and len(set(checklist)) == 1:
  106.                 return row
  107.         return []
  108.  
  109.     def is_draw(self) -> bool:
  110.         """Check if the current position is draw
  111.        """
  112.         if len(self.empty_squares) == 0 and len(self.get_connection()) == 0:
  113.             return True
  114.         return False
  115.  
  116.     def winner(self) -> Optional[str]:
  117.         """Return the winner of the match if exists
  118.        """
  119.         connection = self.get_connection()
  120.         if len(connection) == 0:
  121.             return None
  122.         elif self.square_value(connection[0]) == self.P1:
  123.             return self.P1
  124.         else:
  125.             return self.P2
  126.  
  127.     def is_gameover(self) -> bool:
  128.         """Check if the current game is terminated
  129.        """
  130.         return self.winner() is not None or self.is_draw()
  131.  
  132.     def _update(self) -> None:
  133.         """Update the status of the game
  134.        """
  135.         self.turn = self.P2 if self.turn == self.P1 else self.P1
  136.         if self.winner() == self.P1:
  137.             self.p1_score += 1
  138.         elif self.winner() == self.P2:
  139.             self.p2_score += 1
  140.  
  141.     def push(self, square: int, value: str) -> None:
  142.         """Store the given value in square index
  143.        """
  144.         self.table[square] = value
  145.  
  146.     def undo(self, square: int) -> None:
  147.         """Clear the value in square index
  148.        """
  149.         self.table[square] = self.EMPTY
  150.  
  151.     def move(self, square: Optional[int]) -> None:
  152.         """Make the given move on the board if available
  153.        """
  154.         if square >= self.size**2 or square < 0 or not self.is_empty(square):
  155.             print("Invalid move!")
  156.             return
  157.         self.push(square, self.turn)
  158.         self._update()
  159.  
  160.     def print(self) -> None:
  161.         """Display the current board
  162.        in command line interface
  163.        """
  164.         if self.winner():
  165.             print("Match Over!")
  166.             print("*"*13)
  167.         else:
  168.             print("Turn->> ", self.turn)
  169.             print('-' * (self.size*5))
  170.         for index, square in self.SQUARES.items():
  171.             r, c = index
  172.             sign = square if self.is_empty(square) else self.square_value(square)
  173.             print(' |', end=' ')
  174.             print(sign, end='')
  175.             if c == self.size-1:
  176.                 print(' |')
  177.                 print('-'*(self.size*5))
  178.         print('*'*(self.size*5))
  179.  
  180.  
  181. if __name__ == "__main__":
  182.     # CLI game for two player mode
  183.     board = Board()
  184.     print("Tic Tac Toe - Duel")
  185.     print("##################")
  186.     board.print()
  187.     running = True
  188.     while running:
  189.         move = int(input(f"Enter {board.turn} 's move: "))
  190.         board.move(move)
  191.         board.print()
  192.         if board.is_gameover():
  193.             running = False
  194.     if board.is_draw():
  195.         print("Draw! What a great match!")
  196.     else:
  197.         print(board.winner(), " Wins....!")
  198.  
Advertisement
Add Comment
Please, Sign In to add comment