我的Tic Tac Toe AI出了什么问题?

时间:2017-01-16 12:01:22

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

我读了一篇关于minimax的教程,并尝试制作一个非常简单的人工智能。 但由于某些原因,代码无法以最佳方式工作,这是我无法找到的。 ai可以放置碎片,但它不是一个聪明的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;
}

2 个答案:

答案 0 :(得分:3)

我发现了一些事情:

  • 循环中通过可能的移动的第一行说board[move[0]][move[1]] = player;。这应该是piece而不是player,现在你的人工智能认为只有人类玩家的一部分才能登上董事会。
  • Minimax应该能够在不到一秒的时间内轻松搜索完整的游戏树。因此,我建议允许搜索尽可能深的搜索,而不是限制为1的搜索深度。这也将消除创建启发式评估函数的需要;你只有得分才能获胜,0分为领带,而失败则为非常负分。我推荐这个的主要原因是我怀疑评估功能可能有问题,但我不确定,因为我没有详细检查。如果您确实坚持尽早终止搜索并使用启发式评估功能,则需要确保该功能是对称的&#39;&#39;。有了这个,我的意思是从一个玩家的角度评估棋盘应该始终导致完全 -1次同一个棋盘的得分从对手的视角。

答案 1 :(得分:1)

minimax按行/列对返回移动,而非分数。所以

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

毫无意义。它可能导致第3行的任何移动看起来都比移动到第1行或第2行更好。

minmax需要提交 除了最好的举动外,还有一个得分。