Search code examples
c++artificial-intelligencetic-tac-toeminimax

Tic tac toe Minimax Algorithm Having Weird Behavior (C++)


The other day, I wrote a console game of Tic-Tac-Toe in c++ for my son. He wanted me to add a computer, and I ended us using the minimax algorithm for the first time. I did some quick testing, but really just gave my laptop to my son as soon as it was printing stuff, who played with it for a couple minuets. I looked over his sholder once or twice, and noticed that it wasn't playing optimally, iv'e been trying to debug it, but I can't see where it goes wrong. I tried getting rid of alpha beta prunning, but that did not change anything.

For context, on the board the computer is -1, blank is 0, and the player is 1.

Here is the minimax function:

int minimax(int board[9], int depth, int alpha, int beta, bool isMaxizimaizingPlayer)
{
    bool found = false;
    for (int i = 0; i < 9; i++)
    {
        if (board[i] == 0)
        {
            found = true;
        }
    }
    if (!found)
    {
        return eval(board);
    }
    if (depth == 0 || eval(board) != 0)
    {
        return eval(board);
    }
    if (isMaxizimaizingPlayer) 
    {
        int maxEval = -2;
        for (int spot = 0; spot < 9; spot++) 
        {
            if (board[spot] == 0)
            {
                board[spot] = 1;
                int e = minimax(board, depth - 1, alpha, beta, false);
                if (e > maxEval)
                {
                    maxEval = e;
                }
                //if (beta < alpha) 
                //{
                //  break;
                //}
                board[spot] = 0;
            }
        }
        return maxEval;
    }
    else {
        int minEval = 2;
        for (int spot = 0; spot < 9; spot++)
        {
            if (board[spot] == 0)
            {
                board[spot] = -1;
                int e = minimax(board, depth - 1, alpha, beta, true);
                if (e < minEval)
                {
                    minEval = e;
                }
                //if (beta < alpha)
                //{
                //  break;
                //}
                board[spot] = 0;
            }
        }
        return minEval;
    }
}

To be compleate, here is my eval function:

int eval(int board[9]) 
{
    /*horizontial*/
    for (int i = 0; i < 3; i++) 
    {
        if (board[i * 3] == board[i * 3 + 1] && board[i * 3 + 2] == board[i * 3] && board[i * 3] != 0) 
        {
            return board[i * 3];
        }
    }
    /*vertical*/
    for (int i = 0; i < 3; i++)
    {
        if (board[i] == board[i + 3] && board[i] == board[i + 6] && board[i] != 0)
        {
            return board[i];
        }
    }
    /*Both diags*/
    if (board[4] != 0) {
        if (board[0] == board[4] && board[0] == board[8])
        {
            return board[4];
        }
        if (board[2] == board[4] && board[4] == board[6])
        {
            return board[4];
        }
    }
    return 0;
}

And here is the inital call:

            int spot = 0;
            int minEval = 2;
            for (int i = 0; i < 9; i++) 
            {
                if (board[i] == 0) 
                {
                    board[i] = -1;
                    int score = minimax(board, 3, -2, 2, false);
                    if (score < minEval) {
                        minEval = score;
                        spot = i;
                    }
                    board[i] = 0;
                }
            }
            std::cout << "The computer went in spot " << spot + 1 << std::endl;
            board[spot] = -1;
            printBoard(board);

Solution

  • It looks like you only call minimax with a depth of three, so the algorithm will only look up to three moves ahead, if you want optimal play you need to set the depth to > 9, so that the agent is always looking ahead to the end of the game.