Search code examples
javarecursionartificial-intelligencetic-tac-toeminimax

miniMax algorithm in Java


I'm currently not satisfied with the AI I'm programming. The AI is supposed to get the best score for each move in a 3x3 board (TicTacToe).

The possible scores are -1 (Lose), 0 (Tie) and 1 (Win).

First the method makeTurn() is called, which then calls the method containing the miniMax algorithm.

public void makeTurn(Button[][] currentBoard) {                                                 // Calculating best move using miniMax algorithm
        AIcheck = new Check(currentBoard);
        int bestScore = Integer.MIN_VALUE;
        int[] bestMove = new int[2];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (currentBoard[i][j].getText().equals("")) {
                    currentBoard[i][j].setText("O");
                    int score = calcScore(currentBoard, 0, false);
                    System.out.println(score);
                    currentBoard[i][j].setText("");
                    if (score > bestScore) {
                        bestScore = score;
                        bestMove = new int[]{i, j};

                    }
                }
            }
        }
        Board.getInstance().getField(bestMove[0], bestMove[1]).performClick();
    }

private int calcScore(Button[][] currentBoard, int depth, boolean isMax) {                      // MiniMax Algorithm, calculating score for each branch via recursive execution
        int score;
        if (AIcheck.checkWin()) {
            return (Util.getInstance().getTurnCounter() % 2) == 0 ? 1 : -1;
        } else if (AIcheck.checkTie()) {
            return 0;
        }
        int bestScore = isMax ? Integer.MIN_VALUE : Integer.MAX_VALUE;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (currentBoard[i][j].getText().equals("")) {
                    if (isMax) {
                        currentBoard[i][j].setText("O");
                    } else {
                        currentBoard[i][j].setText("X");
                    }
                    score = calcScore(currentBoard, depth + 1, !isMax);
                    currentBoard[i][j].setText("");
                    bestScore = isMax ? Math.max(bestScore, score) : Math.min(bestScore, score);
                }
            }
        }
        return bestScore;
    }

I'm using isMax to determine if it's the maximizer's turn or not, also using turnCounter % 2 to determine which player's turn it is, since they take turns.

Yet still the AI is not preventing my win, it more of seems like it just goes from one field to next, instead of choosing the optimal field. How would I be able to implement the miniMax algorithm properly? Thanks a lot!

Example:

[]|[]|[]

[]|[]|[]

[X]|[]|[]


[O]|[]|[]

[]|[]|[]

[X]|[]|[]


[O]|[]|[]

[]|[]|[]

[X]|[]|[X]


[O]|[O]|[]

[]|[]|[]

[X]|[]|[X]


[O]|[O]|[X]

[]|[]|[]

[X]|[]|[X]


[O]|[O]|[X]

[O]|[]|[]

[X]|[]|[X]


[O]|[O]|[X]

[O]|[X]|[] I win, also it shows how the AI seems to just take the next spot (from left to right)

[X]|[]|[X]


Solution

  • I think the problem is how you determine who won in calcScore. You use Util.getInstance().getTurnCounter(), but you don't seem to be updating the counter in the recursive calls. You can instead just use depth % 2 or isMax for that:

    if (AIcheck.checkWin()) {
        return isMax ? -1 : 1;
    }