Java 什么';我的井字游戏有什么问题吗?

Java 什么';我的井字游戏有什么问题吗?,java,artificial-intelligence,tic-tac-toe,minimax,Java,Artificial Intelligence,Tic Tac Toe,Minimax,我读了一篇关于minimax的教程,并试图制作一个tac-tac-toe人工智能。 但是,由于某种原因,代码不能最佳工作,我找不到。人工智能可以放置碎片,但它不是智能人工智能。我希望它是不可战胜的。深度越高,ai变得越愚蠢。 “游戏”是我的另一个类,实际的游戏在那里 private Game game; private Piece[][] board; private Piece ai = Piece.CIRCLE; private Piece player = Piece.CROSS; pu

我读了一篇关于minimax的教程,并试图制作一个tac-tac-toe人工智能。 但是,由于某种原因,代码不能最佳工作,我找不到。人工智能可以放置碎片,但它不是智能人工智能。我希望它是不可战胜的。深度越高,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;
}
私人游戏;
私有件[][]板;
私有工件ai=工件圆;
私人棋手=棋子.CROSS;
公共AI(游戏){
这个游戏=游戏;
this.board=game.getBoard();
}
公共int[]移动(){
int[]结果=极小极大值(1,ai);
返回新的int[]{result[1],result[2]};
}
私有整数[]最小最大值(整数深度,单件){
List possibleMoves=generateMoves();
int bestScore=(工件==ai)?Integer.MIN_值:Integer.MAX_值;
int-currentScore;
int bestRow=-1;
int-bestCol=-1;
if(possibleMoves.isEmpty()| | depth==0){
//游戏结束或达到深度
最佳分数=评估();
}
否则{
for(int[]移动:可能移动){
//为玩家试试这个动作
棋盘[移动[0]][移动[1]]=玩家;
如果(件==ai){//ai是最大化玩家
currentScore=minimax(深度-1,玩家)[0];
如果(当前分数>最佳分数){
最佳分数=当前分数;
bestRow=移动[0];
bestCol=move[1];
}
}
否则{//player将最小化player
currentScore=minimax(深度-1,ai)[0];
如果(当前分数<最佳分数){
最佳分数=当前分数;
bestRow=移动[0];
bestCol=move[1];
}
}
//撤消移动
单板[move[0]][move[1]]=null;
}
}
返回新的int[]{bestScore,bestRow,bestCol};
}
私有列表generateMoves(){
List possibleMoves=new ArrayList();
//如果比赛结束
if(game.getWinner()!=null){
return possibleMoves;//返回空列表
}
//将可能的移动添加到列表中
对于(int x=0;x<3;x++){
对于(int y=0;y<3;y++){
if(game.getBoard()[x][y]==null){
add(新的int[]{x,y});
}
}
}
返回可能的动作;
}
private int evaluate(){
智力得分=0;
//评估
分数+=评估线(0,0,0,1,0,2);//第0行
分数+=评估线(1,0,1,1,1,2);//第1行
分数+=评估线(2,0,2,1,2,2);//第2行
分数+=评估线(0,0,1,0,2,0);//列0
分数+=评估线(0,1,1,1,2,1);//列0
分数+=评估线(0,2,1,2,2,2);//列0
分数+=评估线(0,0,1,1,2,2);//诊断1
分数+=评估线(0,2,1,1,2,0);//诊断2
返回分数;
}
//返回+100、+10、+1表示人工智能的3-、2-、1-in-a-line
//返回-100,-10,-1代表3-,2-,1-在一条线上代表玩家
//否则返回0
私有int-evaluateLine(int-row1、int-col1、int-row2、int-col2、int-row3、int-col3){
智力得分=0;
//第一单元
if(线路板[row1][col1]==ai){
得分=1分;
}
else if(棋盘[row1][col1]==玩家){
得分=-1;
}
//第二单元
if(板[row2][col2]==ai){
如果(分数=1){//1是ai
得分=10分;
}
如果(分数==-1){//board1是玩家,则为else
返回0;
}
否则{//board1为空
得分=1分;
}
}
else if(棋盘[row2][col2]==玩家){
如果(分数==-1){//board1是玩家
分数=-10;
}
否则,如果(分数==1){//1是ai
返回0;
}
否则{//board1为空
得分=-1;
}
}
//第三单元
if(板[row3][col3]==ai){
如果(分数>0){//board1和/或board2为ai
分数*=10;
}
否则,如果(分数<0){//board1和/或board2是玩家
返回0;
}
否则{//board1和/或board2为空
得分=1分;
}
}
else if(棋盘[row3][col3]==玩家){
如果(分数<0){//board1和/或board2是玩家
分数*=10;
}
如果(得分>1){//board1和/或board2为ai,则为else
返回0;
}
否则{//board1和/或board2为空
得分=-1;
}
}
返回分数;
}

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

currentScore = minimax(depth - 1, player)[0];
毫无意义。这可能会导致移动到第3行比移动到第1行或第2行看起来更好

minmax
需要手动操作

除了最佳移动之外,还返回一个分数。

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

currentScore = minimax(depth - 1, player)[0];
毫无意义。这可能会导致移动到第3行比移动到第1行或第2行看起来更好

minmax
需要手动操作

除了最精彩的一步之外,我还记下了一个分数。

我注意到了以下几点:

  • 循环中的第一行表示
    board[move[0]][move[1]]=player。那应该是
    piece
    而不是
    player
    ,现在你的AI认为只有人类玩家的片段才会出现在棋盘上
  • 极小极大应该很容易在不到一秒钟的时间内搜索到完整的博弈树。因此,我建议允许搜索任意深度,而不是将搜索深度限制为1。这也将消除创建启发式评估函数的需要;赢了你只会给一个高分,平了你只会给0分,输了你只会给一个非常负的分数。我建议这样做的主要原因是,我怀疑求值函数也可能有问题,尽管我不确定,因为我不知道