Home > Blockchain >  Minimax algorithm not working for Tic Tac Toe in Python
Minimax algorithm not working for Tic Tac Toe in Python

Time:12-19

I recently tried creating a simple Tic Tac Toe AI with minimax (with help from YouTube), but I can't get it to work. The algorithm just spits out the first value it checks instead of going through all of them and giving the best one.

I tried copying the code from the YouTube video but it still doesn't work, can someone tell me what's wrong?

import math
import random

print()

board = {1: '   ', 2: '   ', 3: '   ',
         4: '   ', 5: '   ', 6: '   ',
         7: '   ', 8: '   ', 9: '   '}
computerLetter = 'X'
playerLetter = 'O'


def print_board(board=board):
    for i in range(1, 8, 3):
        print('|'   board[i]   '|'   board[i   1]   '|'   board[i   2]   '|')

        if i < 7:
            print('-' * 13)

    print()


def space_is_free(position):
    if board[position] == '   ':
        return True
    else:
        return False


def free_spaces(board=board):

    freeSpaces = 0
    for key in board.keys():
        if key == '   ':
            freeSpaces  = 1

    return freeSpaces


def make_move(letter, position):

    if space_is_free(position):

        board[position] = ' '   letter   ' '
        print_board(board)

        if check_for_win(board):

            if letter == 'O':
                print("You win!!")
                exit()
            else:
                print("The computer wins. Better luck next time!")
                exit()

        elif check_for_tie(board):
            print("It's a tie! Well played.")
            exit()

    else:

        print("Invalid choice.")
        position = int(input("Enter new position: "))
        make_move(letter, position)


def check_for_win(board=board):

    if board[1] == board[2] == board[3] != '   ' or board[4] == board[5] == board[6] != '   ' or board[7] == board[8] \
            == board[9] != '   ' or board[1] == board[4] == board[7] != '   ' or board[2] == board[5] == board[6] != \
            '   ' or board[3] == board[6] == board[9] != '   ' or board[1] == board[5] == board[9] != '   ' or board[3]\
            == board[5] == board[7] != '   ':
        return True
    else:
        return False


def check_for_win_letter(letter):

    if board[1] == board[2] == board[3] == ' '   letter   ' ' or board[4] == board[5] == board[6] == ' '   letter   ' '\
            or board[7] == board[8] == board[9] == ' '   letter   ' ' or board[1] == board[4] or board[7] == ' '  \
            letter   ' ' or board[2] == board[5] or board[6] == ' '   letter   ' ' or board[3] == board[6] or board[9]\
            == ' '   letter   ' ' or board[1] == board[5] == board[9] == ' '   letter   ' ' or board[3] == board[5] ==\
            board[7] == ' '   letter   ' ':
        return True
    else:
        return False


def check_for_tie(board=board):

    for key in board.keys():
        if board[key] == '   ':
            return False
    else:
        return True


def player_move(playerLetter='O'):

    if free_spaces(board) >= 9:
        print_board(board)

    position = int(input("Enter position (1-9): "))
    make_move(playerLetter, position)


def computer_move(computerLetter='X'):

    if free_spaces(board) == 9:
        make_move(computerLetter, 5)

    else:

        bestScore = -math.inf
        bestPosition = 0

        for key in board.keys():
            if space_is_free(key):
                board[key] = ' '   computerLetter   ' '
                score = minimax(board, 0, False)
                board[key] = '   '

                if score > bestScore:
                    bestScore = score
                    bestPosition = key

        make_move(computerLetter, bestPosition)
        print(f"Computer moves to {bestPosition}.")


def minimax(board, depth, isMaximising):

    if check_for_win_letter('X'):
        return 1 * (free_spaces(board)   1)

    elif check_for_win_letter('O'):
        return -1 * (free_spaces(board)   1)

    elif check_for_tie(board):
        return 0

    if isMaximising:

        bestScore = -math.inf

        for key in board.keys():

            if space_is_free(key):
                board[key] = ' '   computerLetter   ' '
                score = minimax(board, depth   1, False)
                board[key] = '   '
                bestScore = max(score, bestScore)

        return bestScore

    else:

        bestScore = math.inf

        for key in board.keys():

            if space_is_free(key):
                board[key] = ' '   playerLetter   ' '
                score = minimax(board, depth   1, True)
                board[key] = '   '
                bestScore = min(score, bestScore)

        return bestScore


while not check_for_win(board):
    computer_move('X')
    player_move('O')

# gameState = input("Would you like to play again? (y/n)")
#
# if gameState.lower() == 'y':
#     main()
# elif gameState.lower() == 'n':
#     exit()
# else:
#     print("Invalid choice.")

I tried changing the computer and player letters, and whether the computer was maximising or minimising but it didn't work.

CodePudding user response:

I think I have found what is wrong with your code, in the minmax function the first if, elif, else statement always ends with a return statement.

def minimax(board, depth, isMaximising):

if check_for_win_letter('X'):
    return 1 * (free_spaces(board)   1)

elif check_for_win_letter('O'):
    return -1 * (free_spaces(board)   1)

elif check_for_tie(board):
    return 0

The else statement is the reason it is failing.

When a return statement is called, it ends the function returning the variable stated, in this case it will always be a number between -9 and 9, and does not run the next block of code, ruining the computer's process to find the best/worst place to play. the else statement means that even if the previous statements are false, it will always return zero, ending the function and halting the process of the next block of code.

I hope this helps! :)

CodePudding user response:

Okay I figured out the problem, it was actually a bunch of logical errors in the functions which were checking for a winner and the winner letter, a few typos per say.

**

  • Error 1:

**

def check_for_win(board=board):

    if board[1] == board[2] == board[3] != '   ' or board[4] == board[5] == board[6] != '   ' or board[7] == board[8] \
            == board[9] != '   ' or board[1] == board[4] == board[7] != '   ' or ****board[2] == board[5] == board[6]**** != \ # board[6] should be board[8]
            '   ' or board[3] == board[6] == board[9] != '   ' or board[1] == board[5] == board[9] != '   ' or board[3]\
            == board[5] == board[7] != '   ':
        return True

**

  • Error 2:

**

def check_for_win_letter(letter):

if board[1] == board[2] == board[3] == ' '   letter   ' ' or board[4] == board[5] == board[6] == ' '   letter   ' '\
        or board[7] == board[8] == board[9] == ' '   letter   ' ' or board[1] == board[4] ****or board[7]**** == ' '  \
        letter   ' ' or board[2] == board[5] ****or board[6]**** == ' '   letter   ' ' or board[3] == board[6] ****or board[9]****\
        == ' '   letter   ' ' or board[1] == board[5] == board[9] == ' '   letter   ' ' or board[3] == board[5] ==\
        board[7] == ' '   letter   ' ':
    return True

The ones statements within asterisks (*) are the errors, the or statements should be '==' and the board[6] should again be board[8].

  • Related