Search code examples
javaartificial-intelligenceminimax

Minimax value issue - Java


I have looked everywhere for answers for fixing my code but after long hours spent trying to debug it I find myself hopelessly stuck. The problem is that my minimax function will not return the correct values for the best possible move, I even attempted to fix it by storing the best first moves (when depth = 0), but if the solution is not obvious, then the algorithm fails horribly. I also tried modifying the return values from the base cases in order to prioritize earlier wins, but this didn't solve the problem.

Currently I am testing the function on a TicTacToe board and the helper classes (Eg getMoves() or getWinner are working properly), I know my style is not the most efficient but I needed the code to be fairly explicit. By adding a bunch of print statements I realized that under some circumstances my bestFinalMoves ArrayList was not modified, so this may be related to the issue. Another related problem is that unless the algorithm finds a direct win (in the next move), then instead of choosing a move that may lead to a future win or tie by blocking a square that leads to an immediate block, it just yields the space for the minimizing player to win.

For example on the board:

aBoard= new int[][] {
                {0,1,0}, // 1 is MAX (AI), -1 is MIN (Human)
                {-1,0,0},
                {-1,0,0}
        };

Yields the incorrect result of 2,0, where it is obvious that it should be 0,0, so that it blocks the win for the minimizing player, and the bestFinalMoves ArrayList is empty.

 private result miniMaxEnd2(Board tmpGame, int depth){
    String winner =  tmpGame.whoWon();
    ArrayList<Move> myMoves = tmpGame.getMoves();

    if (winner == 'computer'){ //Base Cases
        return new result(1000);
    }else if (winner == 'human'){
        return new result(-1000);
    }
    else if (winner == 'tie'){
        return new result(0);
    }
        if (tmpGame.ComputerTurn) {//MAX
            bestScore = -99999;
            for (Move m : tmpGame.getMoves()){
                Board newGame = new Board(tmpGame,!tmpGame.ComputerTurn, m);
                result aScore = miniMaxEnd2(newGame, depth+1);
                if (aScore.score > bestScore) {
                    bestScore = aScore.score;
                    bestMove = m;
                        if (depth == 0) {
                            bestFinalMoves.add(m);
                        }
                }
            }
            return new result(bestScore, bestMove);
        } else {//MIN
            bestScore = 99999;
            for (Move m : tmpGame.getMoves()) {
                Board newGame = new Board(tmpGame,!tmpGame.ComputerTurn, m);
                result aScore = miniMaxEnd2(newGame, depth + 1);
                if (aScore.score < bestScore) {
                    bestScore = aScore.score;
                    bestMove = m;
                }

            }
            return new result(bestScore,bestMove);

        }

}

I know this was a long post, but I really appreciate your help. The full code can be accessed at https://github.com/serch037/UTC_Connect


Solution

  • The bestScore and bestMove variables must be declared as local variables inside the miniMaxEnd2 method for this logic to work properly. Those variables' values are being replaced by the recursive call.