【问题标题】:What's wrong with my Tic Tac Toe AI?我的井字游戏 AI 出了什么问题?
【发布时间】:2017-01-16 12:01:22
【问题描述】:

我阅读了有关极小极大的教程,并尝试制作一个 tac tac toe AI。 但是由于某种原因,代码不能以最佳方式工作,我找不到。人工智能可以放置碎片,但它不是智能人工智能。我希望它是无与伦比的。深度越高,ai 变得越笨。 “游戏”是我的另一个类,实际游戏在哪里。

private Game game;
private Piece[][] board;
private Piece ai = Piece.CIRCLE;
private Piece player = Piece.CROSS;

public AI(Game game) {
    this.game = game;
    this.board = game.getBoard();

}

public int[] move() {
    int[] result = minimax(1, ai);

    return new int[] {result[1], result[2]};
}

private int[] minimax(int depth, Piece piece) {
    List<int[]> possibleMoves = generateMoves();

    int bestScore = (piece == ai) ? Integer.MIN_VALUE : Integer.MAX_VALUE;
    int currentScore;
    int bestRow = -1;
    int bestCol = -1;

    if (possibleMoves.isEmpty() || depth == 0) {
        // Game over or depth reached
        bestScore = evaluate();
    }
    else {
        for (int[] move : possibleMoves) {
            // Try this move for the player
            board[move[0]][move[1]] = player;
            if (piece == ai) { // ai is maximizing player
                currentScore = minimax(depth - 1, player)[0];

                if (currentScore > bestScore) {
                    bestScore = currentScore;
                    bestRow = move[0];
                    bestCol = move[1];
                }
            }
            else { // player is minimizing player
                currentScore = minimax(depth - 1, ai)[0];

                if (currentScore < bestScore) {
                    bestScore = currentScore;
                    bestRow = move[0];
                    bestCol = move[1];
                }
            }

            // Undo move
            board[move[0]][move[1]] = null;
        }
    }

    return new int[] {bestScore, bestRow, bestCol};
}

private List<int[]> generateMoves() {
    List<int[]> possibleMoves = new ArrayList<int[]>();

    // If game over
    if (game.getWinner() != null) {
        return possibleMoves; // return empty list
    }

    // Add possible moves to list
    for (int x = 0; x < 3; x++) {
        for (int y = 0; y < 3; y++) {
            if (game.getBoard()[x][y] == null) {
                possibleMoves.add(new int[] {x, y});
            }
        }
    }

    return possibleMoves;
}

private int evaluate() {        
    int score = 0;
    // Evaluate
    score += evaluateLine(0, 0, 0, 1, 0, 2); // row 0
    score += evaluateLine(1, 0, 1, 1, 1, 2); // row 1
    score += evaluateLine(2, 0, 2, 1, 2, 2); // row 2
    score += evaluateLine(0, 0, 1, 0, 2, 0); // col 0
    score += evaluateLine(0, 1, 1, 1, 2, 1); // col 0
    score += evaluateLine(0, 2, 1, 2, 2, 2); // col 0
    score += evaluateLine(0, 0, 1, 1, 2, 2); // diag 1
    score += evaluateLine(0, 2, 1, 1, 2, 0); // diag 2

    return score;
}

// Return +100, +10, +1 for 3-, 2-, 1-in-a-line for ai
// Return -100, -10, -1 for 3-, 2-, 1-in a line for player
// Else return 0
private int evaluateLine(int row1, int col1, int row2, int col2, int row3, int col3) {
    int score = 0;

    // First cell
    if (board[row1][col1] == ai) {
        score = 1;
    }
    else if (board[row1][col1] == player) {
        score = -1;
    }

    // Second cell
    if (board[row2][col2] == ai) {
        if (score == 1) { // board1 is ai
            score = 10;
        }
        else if (score == -1) { // board1 is player
            return 0;
        }
        else { // board1 is empty
            score = 1;
        }
    }
    else if (board[row2][col2] == player) {
        if (score == -1) { // board1 is player
            score = -10;
        }
        else if (score == 1) { // board1 is ai
            return 0;
        }
        else { // board1 is empty
            score = -1;
        }
    }

    // Third cell
    if (board[row3][col3] == ai) {
        if (score > 0) { // board1 and/or board2 is ai
            score *= 10;
        }
        else if (score < 0) { // board1 and/or board2 is player
            return 0;
        }
        else { // board1 and/or board2 is empty
            score = 1;
        }
    }
    else if (board[row3][col3] == player) {
        if (score < 0) { // board1 and/or board2 is player
            score *= 10;
        }
        else if (score > 1) { // board1 and/or board2 is ai
            return 0;
        }
        else { // board1 and/or board2 is empty
            score = -1;
        }
    }

    return score;
}

【问题讨论】:

    标签: java artificial-intelligence tic-tac-toe minimax


    【解决方案1】:

    我注意到的几件事:

    • 循环中可能移动的第一行是board[move[0]][move[1]] = player;。那应该是 piece 而不是 player,现在你的 AI 认为只有人类玩家的部分最终会出现在棋盘上。
    • Minimax 应该很容易在不到一秒的时间内搜索完整的游戏树。因此,我建议允许尽可能深入地搜索,而不是将搜索深度限制为 1。这也将消除创建启发式评估函数的需要;你只会给获胜打大分,平局打0分,输打负分。我推荐这个的主要原因是我怀疑评估功能也可能有问题,尽管我不确定,因为我没有详细检查它。如果您确实坚持要尽早终止搜索并使用启发式评估函数,则需要确保该函数是“对称的”。有了这个,我的意思是从一个玩家的角度评估棋盘应该总是导致 完全-1 倍于从一个玩家的角度评估同一棋盘的分数对手。

    【讨论】:

      【解决方案2】:

      minimax 以行/列对的形式返回移动,而不是分数。所以

      currentScore = minimax(depth - 1, player)[0];
      

      没有意义。它可能会导致任何移动到第 3 行看起来比移动到第 1 行或第 2 行更好。

      minmax需要到手
      除了最好的棋步之外,还回一个分数。

      【讨论】:

      • 它返回 int[] {bestScore, bestRow, bestCol} 所以分数是 [0]
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-11
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多