Advertisement
jules0707

tictactoe.py

May 30th, 2023 (edited)
9
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.57 KB | None | 0 0
  1. """
  2. Tic Tac Toe Player
  3. """
  4. import math
  5. import random
  6. import copy
  7. import operator
  8.  
  9. X = "X"
  10. O = "O"
  11. EMPTY = None
  12.  
  13.  
  14. def initial_state():
  15.     """
  16.    Returns starting state of the board.
  17.    """
  18.     return [[EMPTY, EMPTY, EMPTY],
  19.             [EMPTY, EMPTY, EMPTY],
  20.             [EMPTY, EMPTY, EMPTY]]
  21.  
  22.  
  23. def player(board):
  24.     """
  25.    Returns player who has the next turn on a board.
  26.    """
  27.     if terminal(board):
  28.         return -2
  29.     else:  # we asume that the first player is X
  30.         flat_copy = flatten(board)
  31.         return X if flat_copy.count(X) <= flat_copy.count(O) else O
  32.  
  33.  
  34. def actions(board):
  35.     """
  36.    Returns set of all possible actions (i, j) available on the board.
  37.    """
  38.     if terminal(board):
  39.         return -2
  40.     # associate each element to its ordinal value from 0 to 8 tile of grid
  41.     else:
  42.         flat_copy_zip = zip(flatten(board), range(0, 9))
  43.     # transform possible move places to its grid coordinates
  44.     # filter only thoses empty places where player can play ie. None is available
  45.         moves = {map_coordinates(b) for (a, b) in flat_copy_zip if a is None}
  46.     return moves
  47.  
  48.  
  49. def result(board, action):
  50.     """
  51.    Returns the board that results from making move (i, j) on the board.
  52.    """
  53.     check(action)
  54.     who_plays = player(board)  # who's turn it is?
  55.     next_board = copy.deepcopy(board)
  56.     (i, j) = action
  57.     # replaces in place the ith tile with X or O players turn
  58.     next_board[i][j] = who_plays
  59.     return next_board
  60.  
  61.  
  62. def winner(board):
  63.     """
  64.    Returns the winner of the game, if there is one.
  65.    """
  66.     flat_board = flatten(board)
  67.     line_win = line_winner(board)
  68.     column_win = column_winner(flat_board)
  69.     diagonal_win = diagonal_winner(flat_board)
  70.     return game_winner if line_win or column_win or diagonal_win else None
  71.  
  72.  
  73. def terminal(board):
  74.     """
  75.    Returns True if game is over, False otherwise.
  76.    """
  77.     return True if winner(board) or is_full(board) else False
  78.  
  79.  
  80. def utility(board):
  81.     """
  82.    Returns 1 if X has won the game, -1 if O has won, 0 otherwise.
  83.    """
  84.  
  85.     if winner(board):
  86.         if game_winner == O:
  87.             return -1
  88.         elif game_winner == X:
  89.             return 1
  90.     else:
  91.         return 0
  92.  
  93.  
  94. def minimax(board):
  95.     """
  96.    Returns the optimal action for the current player on the board.
  97.    """
  98.     if terminal(board):
  99.         return None
  100.  
  101.     if is_empty(board):  # on the opening move all actions have utility=0
  102.         # any first move is equi-probable of winning?
  103.         return (random.randrange(0, 3), random.randrange(0, 3))
  104.  
  105.     if player(board) == X:  # AI's plays as X
  106.         move_value_pairs = set()
  107.         for move in actions(board):
  108.             v = min_value(result(board, move))
  109.             if v > 0 : #alpha-beta prunning.
  110.                 return move # X has found a winning board no need to search further
  111.             else:
  112.                 move_value_pairs.add((move, v))
  113.             # any pair with higest value is ok
  114.         (best_move, _) = max(move_value_pairs, key=operator.itemgetter(1))
  115.         return best_move
  116.     elif player(board) == O:  # AI plays as O
  117.         move_value_pairs = set()
  118.         for move in actions(board):
  119.             v = max_value(result(board, move))
  120.             if v < 0 : # O has found a winning board
  121.                 return move
  122.             else:
  123.                 move_value_pairs.add((move, v))
  124.         (best_move, _) = min(move_value_pairs, key=operator.itemgetter(1))
  125.         return best_move
  126.  
  127.  
  128. """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  129. XXXXXXXXXXXXXXXXXXXX    UTILITY FUNCTIONS     XXXXXXXXXXXXXXXXXXXXXX
  130. """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  131.  
  132.  
  133. def max_value(board):
  134.     if terminal(board):
  135.         return utility(board)
  136.     else:
  137.         v = -math.inf
  138.         for action in actions(board):
  139.             v = max(v, min_value(result(board, action)))
  140.         return v
  141.  
  142.  
  143. def min_value(board):
  144.     if terminal(board):
  145.         return utility(board)
  146.     else:
  147.         v = math.inf
  148.         for action in actions(board):
  149.             v = min(v, max_value(result(board, action)))
  150.         return v
  151.  
  152.  
  153. def check(action):
  154.     (i, j) = action
  155.     if i not in range(0, 3) or j not in range(0, 3):
  156.         raise Exception()
  157.  
  158.  
  159. def is_full(board):
  160.     flat_board = flatten(board)
  161.     n = flat_board.count(None)
  162.     return False if n > 0 else True
  163.  
  164.  
  165. def is_empty(board):
  166.     flat_board = flatten(board)
  167.     n = flat_board.count(None)
  168.     return True if n == 9 else False
  169.  
  170.  
  171. def line_winner(board):
  172.     line_1_win = winning(board[0])
  173.     line_2_win = winning(board[1])
  174.     line_3_win = winning(board[2])
  175.     # if any 3 in a row combination is valid
  176.     return True if line_1_win or line_2_win or line_3_win else False
  177.  
  178.  
  179. def column_winner(flat_board):
  180.     column1 = flat_board[0:9:3]
  181.     column2 = flat_board[1:9:3]
  182.     column3 = flat_board[2:9:3]
  183.     column_1_win = winning(column1)
  184.     column_2_win = winning(column2)
  185.     column_3_win = winning(column3)
  186.     return True if column_1_win or column_2_win or column_3_win else False
  187.  
  188.  
  189. def diagonal_winner(flat_board):
  190.     diag1 = flat_board[0:9:4]
  191.     diag2 = flat_board[2:8:2]
  192.     diagonal_1_win = winning(diag1)
  193.     diagonal_2_win = winning(diag2)
  194.     return True if diagonal_1_win or diagonal_2_win else False
  195.  
  196.  
  197. def winning(series):  # returns the wieiwie
  198.     # counts number of occurrences of first element
  199.     n = [x for x in series if x is not None].count(series[0])
  200.     if n == 3:
  201.         global game_winner  # we have a winner!
  202.         game_winner = series[0]
  203.         return True
  204.  
  205.  
  206. def flatten(board):  # flatten the list of list board
  207.     return [item for sublist in board for item in sublist]
  208.  
  209.  
  210. def map_coordinates(number):
  211.     if number == 0:
  212.         return (0, 0)
  213.     if number == 1:
  214.         return (0, 1)
  215.     if number == 2:
  216.         return (0, 2)
  217.     if number == 3:
  218.         return (1, 0)
  219.     if number == 4:
  220.         return (1, 1)
  221.     if number == 5:
  222.         return (1, 2)
  223.     if number == 6:
  224.         return (2, 0)
  225.     if number == 7:
  226.         return (2, 1)
  227.     if number == 8:
  228.         return (2, 2)
  229.  
  230.  
  231. def map_action(action):
  232.     if action == (0, 0):
  233.         return 0
  234.     if action == (1, 0):
  235.         return 3
  236.     if action == (2, 0):
  237.         return 6
  238.     if action == (0, 1):
  239.         return 1
  240.     if action == (1, 1):
  241.         return 4
  242.     if action == (2, 1):
  243.         return 7
  244.     if action == (0, 2):
  245.         return 2
  246.     if action == (1, 2):
  247.         return 5
  248.     if action == (2, 2):
  249.         return 8
  250.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement