Почему моя минимаксная реализация не работает?

#python #algorithm #minimax

#python #алгоритм #минимакс

Вопрос:

В настоящее время я работаю над непревзойденной игрой в крестики-нолики на Python с использованием минимаксного алгоритма. На данный момент я застрял на несколько дней, пытаясь выяснить, почему алгоритм не возвращает правильный результат или ходы для воспроизведения ИИ. В текущем состоянии программы, если я выполняю первый ход (X) в верхнем левом углу, минимакс возвращает значение 0, что кажется правильным, поскольку компьютер может только связать. Однако это должно применяться ко всем углам, и любой начальный ввод в нижней строке возвращает -1, что неверно. Лучший ход, который возвращается, также фактически не является лучшим ходом. Любой ввод будет оценен, подсказки будут предпочтительнее, чем полный ответ. Я включил соответствующий код ниже:

    #executes on odd numbered turns (AI goes second) Currently configured with print statements for debugging
    def AI_Logic():
      score = minimax(Board, False)
      x, y = bestmove
      Board[x][y] = 0
      print(count)
      print(bestmove)
      print(score)
      print(Board)
      Turn  = 1

def minimax(Board, Maxplayer):
    global bestmove
    global count

    count  = 1
    # Checks if the board is full or if a player has won
    if is_Full(Board) or has_Won(Board) == True:

        # Checks for wins, if no wins exists return 0
        if has_Won(Board) == False:
            return 0

        # If O has won , return 1
        elif who_Won(Board) == 0:
            return 1 

        # If X has won, return -1
        elif who_Won(Board) == 1:
            return -1 

    if Maxplayer == True:
        maxscore = float("-inf")
        for x in range(3):
            for y in range(3):
                if Board[x][y] == None:
                    Board[x][y] = 0
                    score = minimax(Board, False)
                    Board[x][y] = None
                    if score > maxscore:
                        bestmove = (x, y)
                    maxscore = max(maxscore, score)

        return maxscore

    else:
        minscore = float("inf")
        for x in range(3):
            for y in range(3):
                if Board[x][y] == None:
                    Board[x][y] = 1
                    score = minimax(Board, True)
                    Board[x][y] = None
                    minscore = min(minscore, score)

        return minscore


def is_Full(Board):
    if any(None in sublist for sublist in Board):
        return False
    else:
        return True

def who_Won(Board):
    global hasWon
    # Checks for three of a kind in first column
    if Board[0][0] == Board[1][0] and Board[0][0] != None:
        if Board[1][0] == Board[2][0]:
            hasWon = 1
            return Board[2][0]
    if Board[0][0] == Board[0][1] and Board[0][0] != None:
        if Board[0][1] == Board[0][2]:
            hasWon = 1
            return Board[0][2]
    # Checks for diag win top Left to bottom right
    if Board[0][0] == Board[1][1] and Board[0][0] != None:
        if Board[1][1] == Board[2][2]:
            hasWon = 1
            return Board[2][2]
    # Checks for diag win bottom left to top right
    if Board[0][2] == Board[1][1] and Board[0][2] != None:
        if Board[1][1] == Board[2][0]:
            hasWon = 1
            return Board[2][0]
    # Checks for center column win
    if Board[0][1] == Board[1][1] and Board[0][1] != None:
        if Board[1][1] == Board[2][1]:
            hasWon = 1
            return Board[2][1]
    # Checks for right column win:
    if Board[0][2] == Board[1][2] and Board[0][2] != None:
        if Board[1][2] == Board[2][2]:
            hasWon = 1
            return Board[2][2]
    # Checks for second row win:
    if Board[1][0] == Board[1][1] and Board[1][0] != None:
        if Board[1][1] == Board[1][2]:
            hasWon = 1
            return Board[1][2]
    # Checks for third row win:
    if Board[2][0] == Board[2][1] and Board[2][0] != None:
        if Board[2][1] == Board[2][2]:
            hasWon = 1
            return Board[2][2]


def has_Won(Board):

    # Checks for three of a kind in first column
    if Board[0][0] == Board[1][0] and Board[0][0] != None:
        if Board[1][0] == Board[2][0]:
            return True
    if Board[0][0] == Board[0][1] and Board[0][0] != None:
        if Board[0][1] == Board[0][2]:
            return True
    # Checks for diag win top Left to bottom right
    if Board[0][0] == Board[1][1] and Board[0][0] != None:
        if Board[1][1] == Board[2][2]:
            return True
    # Checks for diag win bottom left to top right
    if Board[0][2] == Board[1][1] and Board[0][2] != None:
        if Board[1][1] == Board[2][0]:
            return True
    # Checks for center column win
    if Board[0][1] == Board[1][1] and Board[0][1] != None:
        if Board[1][1] == Board[2][1]:
            return True
    # Checks for right column win:
    if Board[0][2] == Board[1][2] and Board[0][2] != None:
        if Board[1][2] == Board[2][2]:
            return True
    # Checks for second row win:
    if Board[1][0] == Board[1][1] and Board[1][0] != None:
        if Board[1][1] == Board[1][2]:
            return True
    # Checks for third row win:
    if Board[2][0] == Board[2][1] and Board[2][0] != None:
        if Board[2][1] == Board[2][2]:
            return True

    return False

# Checks the position of a mouse click and draws an X/O, Appends the Board matrix with a 1 in the correct spot to reflect an X, 0 to relfect O
def draw_X(x, y):
    global Turn
    # Checks if turn is an even number (i.e x's turn)
    if Turn % 2 == 0:
        # Series of statements checking the x and y pos of the mouse. Each mouse click lies in a specific box, draw the X/O in the center of the box,
        # making sure there is nothing in the box, and not to overwrite if an X or O already exist.
        if x < WIDTH / 3 and y < HEIGHT/3:
            if Board[0][0] == None:
                Board[0][0] = 1
                WIN.blit(X, (60, 60))
                # Increases Turn after each executed x or O drawing
                Turn  = 1
        elif x < WIDTH - WIDTH / 3 and y < HEIGHT/3:
            if Board[0][1] == None:
                Board[0][1] = 1
                WIN.blit(X, (WIDTH / 3   60, 60))
                Turn  = 1
        elif x < WIDTH and y < HEIGHT/3:
            if Board[0][2] == None:
                Board[0][2] = 1
                WIN.blit(X, (WIDTH - WIDTH / 3   60, 60))
                Turn  = 1
        elif x < WIDTH / 3 and y < HEIGHT - HEIGHT/3:
            if Board[1][0] == None:
                Board[1][0] = 1
                WIN.blit(X, (60, HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH - WIDTH / 3 and y < HEIGHT - HEIGHT/3:
            if Board[1][1] == None:
                Board[1][1] = 1
                WIN.blit(X, (WIDTH / 3   60, HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH and y < HEIGHT - HEIGHT/3:
            if Board[1][2] == None:
                Board[1][2] = 1
                WIN.blit(X, (WIDTH - WIDTH / 3   60, HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH / 3 and y < HEIGHT:
            if Board[2][0] == None:
                Board[2][0] = 1
                WIN.blit(X, (60, HEIGHT - HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH - WIDTH / 3 and y < HEIGHT:
            if Board[2][1] == None:
                Board[2][1] = 1
                WIN.blit(X, (WIDTH / 3   60, HEIGHT - HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH and y < HEIGHT:
            if Board[2][2] == None:
                Board[2][2] = 1
                WIN.blit(X, (WIDTH - WIDTH / 3   60, HEIGHT - HEIGHT / 3   60))
                Turn  = 1

    # On odd number turns, O will be drawn onto the board:
    else:

        if x < WIDTH / 3 and y < HEIGHT/3:
            if Board[0][0] == None:
                Board[0][0] = 0
                WIN.blit(O, (60, 60))
                Turn  = 1
        elif x < WIDTH - WIDTH / 3 and y < HEIGHT/3:
            if Board[0][1] == None:
                Board[0][1] = 0
                WIN.blit(O, (WIDTH / 3   60, 60))
                Turn  = 1
        elif x < WIDTH and y < HEIGHT/3:
            if Board[0][2] == None:
                Board[0][2] = 0
                WIN.blit(O, (WIDTH - WIDTH / 3   60, 60))
                Turn  = 1
        elif x < WIDTH / 3 and y < HEIGHT - HEIGHT/3:
            if Board[1][0] == None:
                Board[1][0] = 0
                WIN.blit(O, (60, HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH - WIDTH / 3 and y < HEIGHT - HEIGHT/3:
            if Board[1][1] == None:
                Board[1][1] = 0
                WIN.blit(O, (WIDTH / 3   60, HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH and y < HEIGHT - HEIGHT/3:
            if Board[1][2] == None:
                Board[1][2] = 0
                WIN.blit(O, (WIDTH - WIDTH / 3   60, HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH / 3 and y < HEIGHT:
            if Board[2][0] == None:
                Board[2][0] = 0
                WIN.blit(O, (60, HEIGHT - HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH - WIDTH / 3 and y < HEIGHT:
            if Board[2][1] == None:
                Board[2][1] = 0
                WIN.blit(O, (WIDTH / 3   60, HEIGHT - HEIGHT / 3   60))
                Turn  = 1
        elif x < WIDTH and y < HEIGHT:
            if Board[2][2] == None:
                Board[2][2] = 0
                WIN.blit(O, (WIDTH - WIDTH / 3   60, HEIGHT - HEIGHT / 3   60))
                Turn  = 1

# 3x3 Matrix used for game logic
Board = [[None]*3, [None]*3, [None]*3]
# Executes every frame, draws the board, checks for wins, and updates the display
def draw_Window():

    draw_Board()
    has_Won(Board)
    pygame.display.update()
# Main Event Loop
def main():
    global Turn
    FPS = 60
    run = True
    WIN.fill((255, 255, 255))
    clock = pygame.time.Clock()

    while run:

        clock.tick(FPS)
        draw_Window()
        # Runs the AI turn on odd numbers
        if Turn % 2 != 0:
            while x:
                AI_Logic()
                x = False
        # Checks for winner
        if has_Won == True:
            pass
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            # Checks if a mouse is clicked. When clicked, it records the x and y pos of the mouse and passes it through the draw_X function
            if event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                draw_X(x, y)
        pygame.display.update()
    pygame.quit()


main()
 

Комментарии:

1. Можем ли мы посмотреть, как вы создаете плату, которую вы передаете в эти функции?

2. Абсолютно, просто добавил больше кода в сообщение, входные данные игрока добавляются через функцию draw_X .

3. Существует много кода, и я не могу его запустить, не могли бы вы поместить все это в pastebin?

4. Вы запускали свою minimax функцию самостоятельно без какого-либо пользовательского интерфейса — например, просто некоторые базовые тесты на разных платах в консольном приложении или среде тестирования?

5. В соответствии с запросом здесь приведен весь код через paste bin. pastebin.com/DjeHMaKD Я отключил некоторые аспекты, которые я переопределю позже (например, фактически нарисовал поворот ИИ в пользовательском интерфейсе). В настоящее время он просто выводит состояние доски после хода ии. Я попробую реализовать тот же алгоритм в более простой программе без пользовательского интерфейса, чтобы увидеть, достигну ли я другого результата. Хорошее предложение.