2017-01-16 42 views
1

我读了一篇关于极大极小的教程,并尝试制作一个tac tac toe AI。 但由于某些原因,代码无法正常工作,这是我找不到的。 ai可以放置碎片,但它不是一个聪明的ai。我预料它是无与伦比的。深度越高,ai的数量就越多。 “游戏”是我的另一个课程,实际的游戏是。我的Tic 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; 
} 

回答

1

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

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

是没有意义的。它可能导致的任何举动排3看起来比任何转至行1或2行。

minmax需要交
回,除了最好的移动的得分要好。

+1

它返回int [] {bestScore,bestRow,bestCol}所以得分是[0] – DingDongDang132

3

一对夫妇的事情,我注意到:

  • 在遍历可能的行动去第一行说board[move[0]][move[1]] = player;。那应该是piece而不是player,现在你的AI认为只有人类玩家的棋子才会成为棋盘上的棋子。
  • Minimax应该很容易在不到一秒的时间内搜索完整的游戏树。因此,我建议允许按照自己喜欢的方式进行深度搜索,而不是将搜索深度限制为1.这样也可以消除创建启发式评估函数的需要;你只会给出一个很大的得分,0分为平局,而一个非常负分的失分。我推荐这个的主要原因是我怀疑评估函数可能有问题,尽管我不确定,因为我没有详细检查它。如果你确实坚持尽早终止搜索并使用启发式评估函数,则需要确保函数是“对称的”。与此同时,我的意思是从一名球员的角度评价董事会应该总是导致正好-1倍同一局的得分从对手的角度进行评估。