0

I'm working on the tic tac toe problem set. The whole game is working correctly, however I'm having some troubles kicking off the AI. I've been running the game with the computer doing random moves, and it works fine.

I've tried implementing the minimax algorithm, and it seems like it works for a while,
until I run into the error TypeError: '>' not supported between instances of 'NoneType' and 'float'

Since I'm an absolute beginner in AI, (and python), I'm not really sure how to solve this.
Regarding the error, I suppose the math.inf and -math.inf are floats, and the state (board) is is the one being NoneType? Why am I getting an error? What value am I suppose to get? Why is this happening?

Thanks in advance for looking into this.

I've pasted all the code with comments

import math
import random
import copy

X = "X"
O = "O"
EMPTY = None

def initial_state():
    """
    Returns starting state of the board.
    """
    return [[EMPTY, EMPTY, EMPTY],
            [EMPTY, EMPTY, EMPTY],
            [EMPTY, EMPTY, EMPTY]]

def player(board):
    """
    Returns player who has the next turn on a board.

    - takes a state, tells whos turn it is
    - assuming x makes a first move on an empty game board, player is x
    - if x has made a move, o is the player
    - takes a game board, and returns whos turn it is
    """
    empty_board = True
    count_x = 0
    count_o = 0
    f_list = []

    """
    for cell in board:
        empty_board = all(c is None for c in cell)
        print(all(c is None for c in cell))
    """

    # Check every item in board.
    # Flatten list, and put all elements in new list, for later use
    # Check if any of the cells contain X or O. If so, the board is not empty,
    # game has began, so we switch empty_board to False
    for cell in board:
        for i in cell:
            f_list.append(i)
            if i == X or i == O:
                empty_board = False

    # If board is empty, return X as the first player
    # else, figure out who's turn is next, by counting how many X and O's on the game board.
    if empty_board == True:
        return X
    else:
        count_x = f_list.count("X")
        count_o = f_list.count("O")
        if count_x > count_o:
           # print("Computer turn")
            return O
        else:
           # print("Player turn")
            return X

def actions(board):
    """
    Returns set of all possible actions (i, j) available on the board.

    - Figures out which possible moves to do next

    """
    available_moves = set()

    for i in range(3):
        for j in range(3):
            if board[i][j] == None:
                available_moves.add((i, j))
    return available_moves

def result(board, action):
    """
    Returns the board that results from making move (i, j) on the board.
    If having a state, and taking an action, we need a result

    - takes the board, and the move as input, and returns the new board
      with the new action
    """

    nboard = copy.deepcopy(board)
    if nboard[action[0]][action[1]] == None:
        nboard[action[0]][action[1]] = player(board)
    else:
        raise ValueError("Already taken")

    return nboard

def winner(board):
    """
    Returns the winner of the game, if there is one.
    """

    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2]:
            return board[i][0]
        elif board[0][i] == board[1][i] == board[2][i]:
            return board[0][i]
        elif board[0][0] == board[1][1] == board[2][2]:
            return board[0][0]
        elif board[0][2] == board[1][1] == board[2][0]:
            return board[0][2]

def terminal(board):
    """
    Returns True if game is over, False otherwise.

    - takes the game board as input. If the game is over, returns true
    """

    # Determine if anyone has 3 in a row
    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2] != None:
            return True
        elif board[0][i] == board[1][i] == board[2][i] != None:
            return True
        elif board[0][0] == board[1][1] == board[2][2] != None:
            return True
        elif board[0][2] == board[1][1] == board[2][0] != None:
            return True

    l_flatten = []

    # Flattens the board, and check if None is in any of the cells.
    # If None is in any cells, the game is not finished, return False.
    # If None is NOT in any cells, the game board is filled out, and the game is over
    for cell in board:
        for i in cell:
            l_flatten.append(i)

    if None not in l_flatten:
        return True
    return False

def utility(board):
    """
    Returns 1 if X has won the game, -1 if O has won, 0 otherwise.
    """

    for i in range(3):
        if board[i][0] == board[i][1] == board[i][2]:
            if board[i][0] == X:
                return 1
            elif board[i][0] == O:
                return -1
            else:
                return 0
        elif board[0][i] == board[1][i] == board[2][i]:
            if board[0][i] == X:
                return 1
            elif board[i][0] == O:
                return -1
            else:
                return 0
        elif board[0][0] == board[1][1] == board[2][2]:
            if board[0][0] == X:
                return 1
            elif board[0][0] == O:
                return -1
            else:
                return 0
        elif board[0][2] == board[1][1] == board[2][0]:
            if board[0][2] == X:
                return 1
            elif board[0][2] == O:
                return -1
            else:
                return 0

def minimax(board):
    """
    Returns the optimal action for the current player on the board.

    should call action to get every move possible for the current player

    """
    moves = actions(board)
    playing = player(board)

    if playing == X:
        return max_value(board)
    else:
        return min_value(board)


    return random.choice(tuple(moves))

def max_value(board):
    if terminal(board):
        print("TERMINAL MAX")
        return utility(board)
    v = -math.inf
    for action in actions(board):
        v = max(v, min_value(result(board, action)))
    return v

def min_value(board):
    if terminal(board):
        print("TERMINAL MIN")
        return utility(board)
    v = math.inf
    for action in actions(board):
        v = min(v, max_value(result(board, action)))
    return v

Traceback:

Traceback (most recent call last):
  File "runner.py", line 115, in <module>
    move = ttt.minimax(board)
  File "tictactoe.py", line 198, in minimax
    return min_value(board)
  File "tictactoe.py", line 218, in min_value
    v = min(v, max_value(result(board, action)))
  File "tictactoe.py", line 209, in max_value
    v = max(v, min_value(result(board, action)))
  File "tictactoe.py", line 218, in min_value
    v = min(v, max_value(result(board, action)))
  File "tictactoe.py", line 209, in max_value
    v = max(v, min_value(result(board, action)))
  File "tictactoe.py", line 218, in min_value
    v = min(v, max_value(result(board, action)))
  File "tictactoe.py", line 209, in max_value
    v = max(v, min_value(result(board, action)))
  File "tictactoe.py", line 218, in min_value
    v = min(v, max_value(result(board, action)))
  File "tictactoe.py", line 209, in max_value
    v = max(v, min_value(result(board, action)))
TypeError: '>' not supported between instances of 'NoneType' and 'float'
1
  • It seems that you are using a "None value" when you call the max() function. For example if you call max(3.5,None) you will get the same error message: TypeError: '>' not supported between instances of 'NoneType' and 'float'. Check if there are any cases where min_value() or max_value() are returning a None. – andreSmol Jun 22 '20 at 14:33

You must log in to answer this question.

Browse other questions tagged .