2012-06-10 11 views
6

मैं वर्तमान में खुद को मिनीमैक्स एल्गोरिदम सिखाने की कोशिश कर रहा हूं और मैंने इसे टिक टैक पैर में जावा में लागू करने की कोशिश की है। हालांकि मेरे एल्गोरिदम में एक बग है और मैं यह नहीं समझ सकता कि इसका क्या कारण है।टिक टैक पैर की अंगुली के लिए मिनीमैक्स एल्गोरिदम में बग

नीचे पूरा स्रोत कोड (! पाठ की दीवार के लिए खेद है) है:

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; 
    } 
} 

यहाँ जब मैं कार्यक्रम चलाने के उत्पादन होता है (कम्प्यूटर चक्र है):

[ ][ ][ ] 
[ ][ ][ ] 
[ ][ ][ ] 
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: 

आप के रूप में पहले कदम के बाद देख सकते हैं, कंप्यूटर सोचता है कि इससे कोई फर्क नहीं पड़ता कि इससे कोई ड्रॉ हो सकता है (स्कोर = 0)।

दूसरे कदम पर मैंने कॉलम 0, पंक्ति 1 पर एक क्रॉस डाला। किसी कारण से, कंप्यूटर सोचता है कि ड्रॉ तक पहुंचने के लिए दो संभावित चाल हैं (स्कोर = 0) और केवल चार चालें खोने के लिए (स्कोर = -1)। इसके बाद यह गलत कदम उठाता है कि यह एक ड्रॉ प्राप्त करेगा।

मैंने पहली बार सोचा था कि हैडऑन विधि में कुछ गड़बड़ है, लेकिन मैंने पंक्ति में तीन प्राप्त करने के सभी 8 तरीकों का परीक्षण किया है और वे सभी सच हो जाते हैं।

मुझे संदेह है कि समस्या बेस्टमोव, अधिकतम या न्यूनतम विधियों में कहीं मौजूद है, लेकिन मैं यह समझने में सक्षम नहीं हूं कि इसका क्या कारण है।

अगर कोई बग पैदा कर रहा है या मेरे रिकर्सिव एल्गोरिदम को बेहतर तरीके से डीबग करने के बारे में कोई सुझाव दे सकता है तो मैं वास्तव में इसकी सराहना करता हूं।

उत्तर

7

मुझे लगता है कि आप min और max के हिस्सों को मिश्रित करते हैं। वर्तमान में, आपका max सबसे खराब संभव कदम (उसके लिए) मानव ले सकता है, कंप्यूटर को ले जा सकने वाले इष्टतम कदम के बजाय, ले सकता है। इसी प्रकार, प्रतिद्वंद्वी के लिए इष्टतम कदम के बजाय कंप्यूटर सबसे खराब चाल का मूल्य लौटा सकता है।

min और max, और findBestMove में PlayerSigns स्विचन द्वारा इसे ठीक min, नहीं max फोन करना चाहिए।

+0

यह अब काम करता है! धन्यवाद! – ScoobyD

संबंधित मुद्दे