井字游戏的Minimax算法不起作用

时间:2020-06-17 02:14:21

标签: java recursion tic-tac-toe minimax

我正在尝试使用简化的minimax算法制作无与伦比的Tic Tac Toe游戏。代码如下:

private static int findBestMove(String[][] board, boolean comp) {
    // comp returns true if the computer is the one looking for the best move
    // findBestMove is always called by the program as findBestMove(board, true)
    // since the computer is the only one that uses it

    // If the board in its current state is a win for the
    // player, return -1 to indicate a loss
    if (playerWon(board)) return -1;

    // If the board in its current state is a win for the
    // computer, return 1 to indicate a win
    if (compWon(board)) return 1;

    // If the board in its current state is a tie
    // return 0 to indicate a tie
    if (tie(board)) return 0;

    // Set the default possible outcome as the opposite of what
    // the respective player wants
    int bestPossibleOutcome = comp ? -1 : 1;

    // Loop through the board looking for empty spaces
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++)

            // Once an empty space is found, create a copy of the board
            // with that space occupied by the respective player 
            if (board[i][j].equals(" ")) {
                String[][] newBoard = new String[3][3];
                for (int a = 0; a < 3; a++) {
                    System.arraycopy(board[a], 0, newBoard[a], 0, 3);
                }
                newBoard[i][j] = comp ? "O" : "X";

                // Recursively call findBestMove() on this copy
                // and see what the outcome is
                int outCome = findBestMove(newBoard, !comp);

                // If this is the computer's turn, and the outcome
                // is higher than the value currently stored as the
                // best, replace it
                if (comp && outCome > bestPossibleOutcome) {
                    bestPossibleOutcome = outCome;


                    // r and c are instance variables that store the row
                    // and column of what the computer's next move should be
                    r = i;
                    c = j;


                // If this is the player's turn, and the outcome
                // is lower than the value currently stored as the
                // best, replace it
                } else if (!comp && outCome < bestPossibleOutcome) {
                    bestPossibleOutcome = outCome;
                }
            }
        }
    }
    // Return the ultimate value deemed to be the best
    return bestPossibleOutcome;
}

这个想法是,在我运行此程序之后,实例变量rc应该分别包含计算机最佳运行的行和列。但是,该程序仅成功防止了大约一半时间的损失,我无法确定另一半是否很幸运,或者该程序是否确实在工作。

我知道计算机将对每种情况做出的响应与每种游戏完全相同。很好。

如果有人想运行该程序,我将在下面提供完整的课程:

import java.util.Scanner;

public class TicTacToe {
    private static int r;
    private static int c;

    private static void printBoard(String[][] board) {
        System.out.println("   0   1   2");
        System.out.println("0  " + board[0][0] + " | " + board[0][1] + " | " + board[0][2] + " ");
        System.out.println("  ---+---+---");
        System.out.println("1  " + board[1][0] + " | " + board[1][1] + " | " + board[1][2] + " ");
        System.out.println("  ---+---+---");
        System.out.println("2  " + board[2][0] + " | " + board[2][1] + " | " + board[2][2] + " ");
    }

    private static boolean playerWon(String[][] board) {
        return playerHasThreeInCol(board) || playerHasThreeInDiag(board) || playerHasThreeInRow(board);
    }

    private static boolean playerHasThreeInRow(String[][] board) {
        for (int i = 0; i < 3; i++) {
            if (board[i][0].equals(board[i][1]) && board[i][0].equals(board[i][2]) && board[i][0].equals("X")) return true;
        }
        return false;
    }

    private static boolean playerHasThreeInCol(String[][] board) {
        for (int i = 0; i < 3; i++) {
            if (board[0][i].equals(board[1][i]) && board[0][i].equals(board[2][i]) && board[0][i].equals("X")) return true;
        }
        return false;
    }

    private static boolean playerHasThreeInDiag(String[][] board) {
        if (board[0][0].equals(board[1][1]) && board[0][0].equals(board[2][2]) && board[0][0].equals("X")) return true;
        return board[0][2].equals(board[1][1]) && board[0][2].equals(board[2][0]) && board[0][2].equals("X");
    }

    private static boolean compWon(String[][] board) {
        return compHasThreeInCol(board) || compHasThreeInDiag(board) || compHasThreeInRow(board);
    }

    private static boolean compHasThreeInRow(String[][] board) {
        for (int i = 0; i < 3; i++) {
            if (board[i][0].equals(board[i][1]) && board[i][0].equals(board[i][2]) && board[i][0].equals("O")) return true;
        }
        return false;
    }

    private static boolean compHasThreeInCol(String[][] board) {
        for (int i = 0; i < 3; i++) {
            if (board[0][i].equals(board[1][i]) && board[0][i].equals(board[2][i]) && board[0][i].equals("O")) return true;
        }
        return false;
    }

    private static boolean compHasThreeInDiag(String[][] board) {
        if (board[0][0].equals(board[1][1]) && board[0][0].equals(board[2][2]) && board[0][0].equals("O")) return true;
        return board[0][2].equals(board[1][1]) && board[0][2].equals(board[2][0]) && board[0][2].equals("O");
    }

    private static boolean tie(String[][] board) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[i][j].equals(" ")) return false;
            }
        }
        return true;
    }

    private static int findBestMove(String[][] board, boolean comp) {
        if (playerWon(board)) return -1;
        if (compWon(board)) return 1;
        if (tie(board)) return 0;
        int bestPossibleOutcome = comp ? -1 : 1;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[i][j].equals(" ")) {
                    String[][] newBoard = new String[3][3];
                    for (int a = 0; a < 3; a++) {
                        System.arraycopy(board[a], 0, newBoard[a], 0, 3);
                    }
                    newBoard[i][j] = comp ? "O" : "X";
                    int outCome = findBestMove(newBoard, !comp);
                    if (comp && outCome > bestPossibleOutcome) {
                        bestPossibleOutcome = outCome;
                        r = i;
                        c = j;
                    } else if (!comp && outCome < bestPossibleOutcome) {
                        bestPossibleOutcome = outCome;
                    }
                }
            }
        }
        return bestPossibleOutcome;
    }

    private static void go() {
        Scanner input = new Scanner(System.in);
        String[][] board = new String[3][3];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                board[i][j] = " ";
            }
        }
        printBoard(board);
        for (int i = 0;; i++) {
            if (i % 2 == 0) {
                while (true) {
                    System.out.println("Enter position: ");
                    String position = input.nextLine();
                    int row, column;
                    try {
                        row = Integer.parseInt(position.substring(0, 1));
                        column = Integer.parseInt(position.substring(1, 2));
                    } catch (Exception e) {
                        System.out.println("Invalid entry. ");
                        continue;
                    }
                    if (row < 0 || row > 2 || column < 0 || column > 2) {
                        System.out.println("That position is not on the board. ");
                        continue;
                    }
                    if (!board[row][column].equals(" ")) {
                        System.out.println("That space is already taken. ");
                        continue;
                    }
                    board[row][column] = "X";
                    break;
                }
            } else {
                System.out.println("\nMy move: ");
                findBestMove(board, true);
                board[r][c] = "O";
            }
            printBoard(board);
            if (playerWon(board)) {
                System.out.println("You win!");
                break;
            } else if (compWon(board)) {
                System.out.println("I win!");
                break;
            } else if (tie(board)) {
                System.out.println("Tie game");
                break;
            }
        }
    }

    public static void main(String[] args) {
        go();
    }
}

我并没有要求任何人为我重写整个内容,但是如果您可以指出任何明显的错误或将我指向正确的方向,那将不胜感激。我也欢迎您提出任何建议或意见。

1 个答案:

答案 0 :(得分:0)

我还没有对其进行广泛的测试,但是我相信我已经解决了这个问题。新代码如下所示:

private static void findBestMove(String[][] board) {
    double bestMove = Double.NEGATIVE_INFINITY;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
             if (board[i][j].equals(" ")) {
                 board[i][j] = "O";
                 double score = minimax(board, false);
                 board[i][j] = " ";
                 if (score > bestMove) {
                      bestMove = score;
                      r = i;
                      c = j;
                 }
             }
         }
     }
}

private static double minimax(String[][] board, boolean comp) {
    if (playerWon(board)) {
        return -1;
    }
    if (compWon(board)) {
        return 1;
    }
    if (tie(board)) return 0;

    double bestScore;
    if (comp) {
         bestScore = Double.NEGATIVE_INFINITY;
         for (int i = 0; i < 3; i++) {
             for (int j = 0; j < 3; j++) {
                 if (board[i][j].equals(" ")) {
                    board[i][j] = "O";
                    double score = minimax(board, false);
                    board[i][j] = " ";
                    bestScore = Math.max(score, bestScore);
                 }
             }
         }
    } else {
         bestScore = Double.POSITIVE_INFINITY;
         for (int i = 0; i < 3; i++) {
              for (int j = 0; j < 3; j++) {
                  if (board[i][j].equals(" ")) {
                      board[i][j] = "X";
                      double score = minimax(board, true);
                      board[i][j] = " ";
                      bestScore = Math.min(score, bestScore);
                  }
              }
          }
     }
     return bestScore;
}

我从下一个移动坐标设置器中抽象出了minimax算法,我认为这可能有所作为。否则,它非常相似。