2012-06-10 7 views
6

私は現在、Minimaxアルゴリズムを自分自身で教えようとしています。私はtic tac toeのjavaで実装しようとしています。私のアルゴリズムにはバグがありますが、何が原因なのかわかりません。以下は Tic Tac ToeのMinimaxアルゴリズムのバグ

が(!テキストの壁のために申し訳ありませんが)完全なソースコードである:あなたのよう

[ ][ ][ ] 
[ ][ ][ ] 
[ ][ ][ ] 
Select column(x-axis). 0, 1 or 2: 1 
Select row(y-axis). 0, 1 or 2: 1 
[ ][ ][ ] 
[ ][x][ ] 
[ ][ ][ ] 
Child Score: 0 
Child Score: 0 
Child Score: 0 
Child Score: 0 
Child Score: 0 
Child Score: 0 
Child Score: 0 
Child Score: 0 
[o][ ][ ] 
[ ][x][ ] 
[ ][ ][ ] 
Select column(x-axis). 0, 1 or 2: 0 
Select row(y-axis). 0, 1 or 2: 1 
[o][ ][ ] 
[x][x][ ] 
[ ][ ][ ] 
Child Score: -1 
Child Score: 0 
Child Score: 0 
Child Score: -1 
Child Score: -1 
Child Score: -1 
[o][ ][o] 
[x][x][ ] 
[ ][ ][ ] 
Select column(x-axis). 0, 1 or 2: 

:私はプログラムを実行するときにここで

public class TicTacToe { 
    private static boolean gameEnded = false; 
    private static boolean player = true; 
    private static Scanner in = new Scanner(System.in); 
    private static Board board = new Board(); 

    public static void main(String[] args){ 
     System.out.println(board); 
     while(!gameEnded){ 
      Position position = null; 
      if(player){ 
       position = makeMove(); 
       board = new Board(board, position, PlayerSign.Cross); 
      }else{ 
       board = findBestMove(board); 
      }    
      player = !player; 
       System.out.println(board); 
       evaluateGame(); 
     } 
    } 

    private static Board findBestMove(Board board) { 
     ArrayList<Position> positions = board.getFreePositions(); 
     Board bestChild = null; 
     int previous = Integer.MIN_VALUE; 
     for(Position p : positions){ 
      Board child = new Board(board, p, PlayerSign.Circle); 
      int current = max(child); 
      System.out.println("Child Score: " + current); 
      if(current > previous){ 
       bestChild = child; 
       previous = current; 
      } 
     } 
     return bestChild; 
    } 

    public static int max(Board board){ 
     GameState gameState = board.getGameState(); 
     if(gameState == GameState.CircleWin) 
      return 1; 
     else if(gameState == GameState.CrossWin) 
      return -1; 
     else if(gameState == GameState.Draw) 
      return 0; 
     ArrayList<Position> positions = board.getFreePositions(); 
     int best = Integer.MIN_VALUE; 
     for(Position p : positions){ 
      Board b = new Board(board, p, PlayerSign.Cross); 
      int move = min(b); 
      if(move > best) 
       best = move; 
     }  
     return best; 
    } 

    public static int min(Board board){ 
     GameState gameState = board.getGameState(); 
     if(gameState == GameState.CircleWin) 
      return 1; 
     else if(gameState == GameState.CrossWin) 
      return -1; 
     else if(gameState == GameState.Draw) 
      return 0; 
     ArrayList<Position> positions = board.getFreePositions(); 
     int best = Integer.MAX_VALUE; 
     for(Position p : positions){ 
      Board b = new Board(board, p, PlayerSign.Circle); 
      int move = max(b); 
      if(move < best) 
       best = move; 
     } 
     return best; 
    } 

    public static void evaluateGame(){ 
     GameState gameState = board.getGameState(); 
     gameEnded = true; 
     switch(gameState){ 
      case CrossWin : 
       System.out.println("Game Over! Cross Won!"); 
       break; 
      case CircleWin : 
       System.out.println("Game Over! Circle Won!"); 
       break; 
      case Draw : 
       System.out.println("Game Over! Game Drawn!"); 
       break; 
      default : gameEnded = false; 
       break; 
     } 
    } 

    public static Position makeMove(){ 
     Position position = null; 
     while(true){ 
      System.out.print("Select column(x-axis). 0, 1 or 2: "); 
      int column = getColOrRow(); 
      System.out.print("Select row(y-axis). 0, 1 or 2: "); 
      int row = getColOrRow(); 
      position = new Position(column, row); 
      if(board.isMarked(position)) 
       System.out.println("Position already marked!"); 
      else break; 
     } 
     return position; 
    } 

    private static int getColOrRow(){ 
     int ret = -1; 
     while(true){ 
      try{ 
       ret = Integer.parseInt(in.nextLine()); 
      } catch (NumberFormatException e){} 
      if(ret < 0 | ret > 2) 
       System.out.print("\nIllegal input... please re-enter: "); 
      else break; 
     } 
     return ret; 
    } 
} 

public enum PlayerSign{ 
    Cross, Circle 
} 

public enum GameState { 
    Incomplete, CrossWin, CircleWin, Draw 
} 

public final class Position { 
    public final int column; 
    public final int row; 

    public Position(int column, int row){ 
     this.column = column; 
     this.row = row; 
    } 
} 

public class Board { 
    private char[][] board; //e = empty, x = cross, o = circle. 

    public Board(){ 
     board = new char[3][3]; 
     for(int y = 0; y < 3; y++) 
      for(int x = 0; x < 3; x++) 
       board[x][y] = 'e'; //Board initially empty 
    } 

    public Board(Board from, Position position, PlayerSign sign){ 
     board = new char[3][3]; 
     for(int y = 0; y < 3; y++) 
      for(int x = 0; x < 3; x++) 
       board[x][y] = from.board[x][y]; 
     board[position.column][position.row] = sign==PlayerSign.Cross ? 'x':'o'; 
    } 

    public ArrayList<Position> getFreePositions(){ 
     ArrayList<Position> retArr = new ArrayList<Position>();  
     for(int y = 0; y < 3; y++) 
      for(int x = 0; x < 3; x++) 
       if(board[x][y] == 'e') 
        retArr.add(new Position(x, y)); 
     return retArr; 
    } 

    public GameState getGameState(){  
     if(hasWon('x')) 
      return GameState.CrossWin; 
     else if(hasWon('o')) 
      return GameState.CircleWin; 
     else if(getFreePositions().size() == 0) 
      return GameState.Draw; 
     else return GameState.Incomplete; 
    } 

    private boolean hasWon(char sign){ //8 ways to win. 
     if(board[1][1] == sign){ 
      if(board[0][0] == sign && board[2][2] == sign) 
       return true; 
      if(board[0][2] == sign && board[2][0] == sign) 
       return true; 
      if(board[1][0] == sign && board[1][2] == sign) 
       return true; 
      if(board[0][1] == sign && board[2][1] == sign) 
       return true; 
      } 
      if(board[0][0] == sign){ 
       if(board[0][1] == sign && board[0][2] == sign) 
        return true; 
       if(board[1][0] == sign && board[2][0] == sign) 
        return true; 
      } 
      if(board[2][2] == sign){ 
       if(board[1][2] == sign && board[0][2] == sign) 
        return true; 
       if(board[2][1] == sign && board[2][0] == sign) 
        return true; 
      } 
      return false; 
    } 

    public boolean isMarked(Position position){ 
     if(board[position.column][position.row] != 'e') 
      return true; 
     return false; 
    } 

    public String toString(){ 
     String retString = "\n"; 
     for(int y = 0; y < 3; y++){ 
      for(int x = 0; x < 3; x++){ 
       if(board[x][y] == 'x' || board[x][y] == 'o') 
        retString += "["+board[x][y]+"]"; 
       else 
        retString += "[ ]"; 
      } 
      retString += "\n"; 
     }  
     return retString; 
    } 
} 

が出力されます(コンピュータは円です)最初の動きの後で見ることができる、コンピュータはそれが何を動かすにせよそれが引き分けを得ることができると思う(スコア= 0)。

何かの理由で、コンピュータは何らかの理由で2つの可能な移動(スコア= 0)と失う4つの移動しかないと考えています(スコア= -1)。それは誤った動きをして、引き分けになると考えている。

私はまずhasWonメソッドに何か問題があったと思っていましたが、私は3つを連続して取得する8つの方法すべてをテストしており、すべてtrueに戻ります。

findBestMove、maxまたはminメソッドのどこかに問題があると思われますが、何が原因なのか正確に把握できていません。

誰かがバグの原因を突き止めたり、再帰アルゴリズムをよりよくデバッグする方法を提案してくれたら、本当に感謝します。

答えて

7

minmaxの部分が混ざっているように見えます。現在のところ、あなたのmaxは、人間が取ることができる最適な移動の代わりに、最悪の可能な移動(彼のために)の値を返します。同様に、minは、コンピューターが最善の移動をする代わりに、最悪の移動の値を返します。

minmaxでPlayerSignsを切り替えることによって、これを修正し、findBestMovemin、ないmaxを呼び出す必要があります。

+0

今すぐ動作します!ありがとう! – ScoobyD