cs50ai ti c ta c toe minimax TypeError: '>' не поддерживается между экземплярами 'NoneType' и 'float' - PullRequest
0 голосов
/ 25 мая 2020

Я работаю над набором задач ti c ta c toe. Вся игра работает правильно, но у меня проблемы с запуском ИИ. Я запускал игру, когда компьютер делал случайные ходы, и она отлично работает.

Я пробовал реализовать алгоритм минимакса, и кажется, что он работает какое-то время,
пока не столкнусь с ошибкой TypeError: '>' not supported between instances of 'NoneType' and 'float'

Так как я абсолютный новичок в AI (и python), я не совсем уверен, как это решить.
Что касается ошибки, я полагаю, что math.inf и -math.inf - это числа с плавающей запятой, а состояние (доска) - это NoneType? Почему я получаю сообщение об ошибке? Какую ценность я предполагаю получить? Почему это происходит?

Заранее спасибо за изучение.

Я вставил весь код с комментариями

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 (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'
...