-3

So I've been looking into creating a simple tic-tac-toe game where the human player plays against an ai run by the minimax algorithm. I have spent the last few days trying to figure these two bugs out but I cant for the life of me seem to. for one, the ai seems sort of predictable and not very good. Secondly, the only way it seems to work is if the ai goes first, if I have the human player go first, the ai just continues to fill the next available spot. Any help would be super appreciated.

Here's my code:

import java.util.Scanner;
public class Game 
{

    static String player = "X";
    static String opponent = "O";
    int row;
    int col;
    public Game(int x, int y)
    {
        row = x;
        col = y;
    }
    public static void main(String[] args)
    {
        Scanner input = new Scanner(System.in);
        String [][] board = new String [3][3];
        fillBoard(board);
        while(true) //Infinite loop only for testing, will change back
        {
            getBestMove(board);
            printBoard(board);
            playerTurn(board, input);
            printBoard(board);
            //System.out.println("Best move: " + bestMove.row + " " + bestMove.col);
        }
        //input.close();
    }
    static int checkState(String [][] board) 
    { 

        for (int row = 0; row<3; row++) //Rows
        { 
            if (board[row][0] == board[row][1] && 
                board[row][1] == board[row][2]) 
            { 
                if (board[row][0]==player) 
                    return -10; 
                else if (board[row][0]==opponent) 
                    return +10; 
            } 
        } 


        for (int col = 0; col<3; col++) //Columns
        { 
            if (board[0][col]==board[1][col] && 
                board[1][col]==board[2][col]) 
            { 
                if (board[0][col]==player) 
                    return -10; 

                else if (board[0][col]==opponent) 
                    return +10; 
            } 
        } 


        if (board[0][0]==board[1][1] && board[1][1]==board[2][2]) //Diagonal
        { 
            if (board[0][0]==player) 
                return -10; 
            else if (board[0][0]==opponent) 
                return +10; 
        } 

        else if (board[0][2]==board[1][1] && board[1][1]==board[2][0]) //Diagonal
        { 
            if (board[0][2]==player) 
                return -10; 
            else if (board[0][2]==opponent) 
                return +10; 
        } 

        return 0; 
    } 

    public static void getBestMove(String[][] board)
    {
        int bestValue = -1000;
        Game bestMove = new Game(-1,-1);

        for(int i = 0; i < 3; i++)
        {
            for(int j = 0; j < 3; j++)
            {
                if(board[i][j] == "-")
                {
                    board[i][j] = player;
                    int currentValue = minimax(board, 0, false);
                    board[i][j] = "-";
                    if(currentValue > bestValue)
                    {
                        bestMove.row = i;
                        bestMove.col = j;
                        bestValue = currentValue;
                    }
                }


            }
        } 
        board[bestMove.row][bestMove.col]= opponent; 
    }
    public static int minimax(String [][] board, int depth, boolean isMaximizer)
    {
        if(checkState(board) != 0)
            return checkState(board);

        if(checkRemainingPlays(board) == false)
            return 0;

        if(isMaximizer)
        {
            int highest = -1000;
            for(int i = 0; i < 3; i++)
            {
                for(int j = 0; j < 3; j++)
                {
                    if(board[i][j] == "-")
                    {
                        board[i][j] = player;
                        highest = Math.max(highest,  minimax(board, depth + 1, !isMaximizer));
                        board[i][j] = "-";
                    }

                }
            }
            return highest;
        }
        else
        {
            int lowest = 1000;
            for(int i = 0; i < 3; i++)
            {
                for(int j = 0; j < 3; j++)
                {
                    if(board[i][j] == "-")
                    {
                        board[i][j] = opponent;
                        lowest = Math.min(lowest,  minimax(board, depth + 1, !isMaximizer));
                        board[i][j] = "-";
                    }
                }
            }
            return lowest;
        }
    }



    public static void playerTurn(String [][] board , Scanner input)
    {
        input = new Scanner(System.in);

        System.out.println("Player 1: ");


        System.out.println("Please enter the index of desired spot (I) ");
        int desiredIndexI = input.nextInt();
        System.out.println("Please enter the index of desired spot (J) ");
        int desiredIndexJ = input.nextInt();
        while(board[desiredIndexI][desiredIndexJ] != "-")
        {
            System.out.println("Please enter the index of desired spot (I) ");
            desiredIndexI = input.nextInt();
            System.out.println("Please enter the index of desired spot (J) ");
            desiredIndexJ = input.nextInt();
        }


        board[desiredIndexI][desiredIndexJ] = player;


    }

    public static boolean checkRemainingPlays(String [][] board)
    {
        for(int i = 0; i < board.length; i++) 
        {
            for(int j = 0; j < board[i].length; j++) 
            {
                if (board[i][j] == "-")
                    return true;
            }
        }
        return false;
    }

    public static void printBoard(String [][] board)
    {
        for(int i = 0; i < board.length; i++) 
        {
            if(i <= 2 && i > 0)
                System.out.println("----------");
            for(int j = 0; j < board[i].length; j++) 
            {
                if(j < 2)
                    System.out.print(board[i][j] + " | ");
                if(j == 2)
                    System.out.println(board[i][j]);
            }
        }
    }
    public static void fillBoard(String [][] board)
    {
        for(int i = 0; i < board.length; i++) 
        {
            for(int j = 0; j < board[i].length; j++) 
            {
                board[i][j] = "-";
            }
        }
    }
}
user3386109
  • 34,287
  • 7
  • 49
  • 68
brokenfulcrum
  • 73
  • 1
  • 4
  • Welcome to Stack Overflow! Please understand that your question boils down to "please help me resolving my complex problem". But we do not regard such requests as valid questions (see [here](https://meta.stackoverflow.com/questions/284236/why-is-can-someone-help-me-not-an-actual-question) for details). It is not realistic to dump so much code here, that people then engage and start to do **your** work of debugging. – GhostCat Jun 25 '19 at 17:53
  • Having said that: in order to debug something like that, simply start with scenarios that are easy to verify, like: have the "AI" look at a board where it can make a winning move immediately. If it fails, debug that failure. Then, write another test, where there is a chance to win in the next move. And so on. It also often helps that you **predict** exactly what kind of computation should happen, to then compare that with the actual results. But as said: that is all a lot of work, and expecting that volunteers on the internet solve your fun project for you ... is rather unrealistic. – GhostCat Jun 25 '19 at 17:54
  • Looks like `getBestMove` and `minimax` are trying to find a move for the `player`. They should be finding a move for the `opponent`. – user3386109 Jun 25 '19 at 18:03
  • btw, to get the code to format correctly, select the code, and then press the code button. The button looks like this `{}` and is at the top of the edit pane. – user3386109 Jun 25 '19 at 18:07
  • Welcome to StackOverflow. Please read and follow the posting guidelines in the help documentation, as suggested when you created this account. [Minimal, complete, verifiable example](https://stackoverflow.com/help/minimal-reproducible-example) applies here. We cannot effectively help you until you post your MCVE code and accurately specify the problem. We should be able to paste your posted code into a text file and reproduce the problem you specified. StackOverflow is not a design, coding, research, or tutorial resource. "Does not work" is not a problem specification. – Prune Jun 26 '19 at 17:01

1 Answers1

0

At first, I'd like to start with the good news. Solving Tic Tac Toe with the minimax algorithm is a great training for beginners in Artificial Intelligence. The problem isn't to easy and it teaches well what AI planning is. Using Java for realizing the game plus the solver is also a good choice, because the language runs everywhere, supports object-oriented programming and is reasonable fast to execute.

Now I'd like to introduce the critical aspects. The first problem is, that AI related problems are quite different from normal computing tasks. If the sourcecode is about painting a AWT Java GUI to the screen, or about how to send a parameter to a class, I'm sure the question can be answered easily. In most cases, AI topics doesn't fail because of programming issues which means how to use a certain programming language but because of the underlying algorithm.

The discussion space in which AI problems are described and solved isn't within the programming domain but within the Gutenberg galaxy. Which means, around TicTacToe gameplaying with Artificial Intelligence and for the Minimax algorithm, there are at least 1000 papers, books and powerpoint presentations available. The task for the newbie isn't to write Java sourcecode, but to read and cite these sources. This helps other to understand the problem and provide detailed feedback.

I know, this moral instruction isn't answering the original question but the aim was to explain why I've pressed the button “migrate the question to https://ai.stackexchange.com/”. In this forum the question will get an answer quickly.

Manuel Rodriguez
  • 734
  • 4
  • 18