2013-08-04 34 views
0

首先,我希望我可以在这里请求一些调试帮助。这就是说, 我已经创建了这个简单的小型tic tac脚趾程序,它基本上完成了,但是这个语义错误一直在困扰着我。Java中基本Tictactoe程序的语义错误

很显然,我花了一些时间,试图找出问题上我自己的,但是你可以说,我已经放弃了对所以这里我现在:)

对于一些简要概述,该板由char ttt [3] [3]类型的数组表示。玩家也char类型的变量,因此它们要么是“X”或“O”和董事会的坐标输入的字母:

样品运行将是这样的:

******************************** 
    ---a------b------c--- 
    |  |  |  | 
    ---d------e------f--- 
    |  |  |  | 
    ---g------h------i--- 
    |  |  |  | 
    --------------------- 
player1: O, it is your turn. 
Select a cell [a, b, c, ... i] 
a 
******************************** 
    ---a------b------c--- 
    | O |  |  | 
    ---d------e------f--- 
    |  |  |  | 
    ---g------h------i--- 
    |  |  |  | 
    --------------------- 
player2: X, it is your turn. 
Select a cell [a, b, c, ... i] 

的数组ttt [3] [3]被初始化,使得每个元素都是''。

大部分程序运行良好。为了尽量节省一些时间,你们这些家伙,我相信下面的方法是完全运行

  • 布尔赢家(焦球员)
  • 布尔gameIsDraw()
  • 无效displayBoard()
  • 字符串playerID(焦球员)
  • 和主要方法

在那里我确实看到了问题最有可能包含我内getPlayerInput(焦球员)方法:

void getPlayerInput(char player) 
{  
    int row = 0; 
    int col = 0; 

    System.out.println(playerID(player) + ", it is your turn."); 
    System.out.println("Select a cell [a, b, c, ... i]"); 

    char answer; 
    answer = scan.next().charAt(0); 

    switch(answer) 
    { 
    case 'a': 
     row = 0; 
     col = 0; 
     break;   
    case 'b': 
     row = 0; 
     col = 1; 
     break;   
    case 'c': 
     row = 0; 
     col = 2; 
     break;   
    case 'd': 
     row = 1; 
     col = 0; 
     break;   
    case 'e': 
     row = 1; 
     col = 1; 
     break;   
    case 'f': 
     row = 1; 
     col = 2; 
     break; 
    case 'g': 
     row = 2; 
     col = 0; 
     break; 
    case 'h': 
     row = 2; 
     col = 1; 
     break; 
    case 'i': 
     row = 2; 
     col = 2; 
     break; 

    default: 
     System.out.println("Invalid location, try again."); 
     getPlayerInput(player);    
    } 

    if(ttt[row][col] != ' ') 
    { 
     System.out.println("This square is taken. Try again."); 
     getPlayerInput(player); 
    } 
    else 
    { 
     ttt[row][col] = player; 
    }    
} 

对我来说,它看起来不错,但我的输出另有指示。该方法包括两个failsafes,

  1. 如果用户输入的东西的板范围外(的“a”到“I”外字符),

  2. ,或者如果用户选择了信/位置在已经被另一个'X'或'O'占据的棋盘上。

在这两种情况下,该方法都会输出一些错误输入,然后再次调用getPlayerInput()。

我通过调试注意到,如果只输入有效输入,程序似乎运行良好。但是,如果输入错误的输入(任一种类型)然后输入有效的输入,有时该方法将打印输入错误仍然输入。

例如,我进入了焦炭

******************************** 
    ---a------b------c--- 
    |  |  |  | 
    ---d------e------f--- 
    |  |  |  | 
    ---g------h------i--- 
    |  |  |  | 
    --------------------- 
player1: O, it is your turn. 
Select a cell [a, b, c, ... i] 
a 
******************************** 
    ---a------b------c--- 
    | O |  |  | 
    ---d------e------f--- 
    |  |  |  | 
    ---g------h------i--- 
    |  |  |  | 
    --------------------- 
player2: X, it is your turn. 
Select a cell [a, b, c, ... i] 
z 
Invalid location, try again. 
player2: X, it is your turn. 
Select a cell [a, b, c, ... i] 
e 
This square is taken. Try again. 
player2: X, it is your turn. 
Select a cell [a, b, c, ... i] 
f 
******************************** 
    ---a------b------c--- 
    | O |  |  | 
    ---d------e------f--- 
    |  | X | X | 
    ---g------h------i--- 
    |  |  |  | 
    --------------------- 
player1: O, it is your turn. 
Select a cell [a, b, c, ... i] 

通知是A-Z-E-F。 'z'显然是一个无效字符,所以该方法按照预期工作(到目前为止),打印出它是无效输入,然后该方法再次运行,要求输入。然后输入'e',这显然是一个有效的位置,但是当显然没有时,该方法打印出“方块已经被占用”。但是,输入一个不同的char'f'可以让我退出它。

最终的结果是玩家'X'有两圈,并填充了'e'和'f'两个方格。

需要注意的是,如果用户不断输入错误的输入,那么他应该被卡在该方法中直到输入有效的输入,但是很明显这种情况下好的输入被错误解释为错误的输入,并且除非输入一个不同的输入实例,否则不能退出循环。

所以,有了这一切,帮助我?无论如何,我非常欣赏的人谁是有耐心看完这么远......

如果你喜欢跑自己的代码,这是源:

import java.util.*; 

class TicTacToe 
{ 
    char ttt[][] = new char[3][3]; 
    static final char player1 = 'O'; 
    static final char player2 = 'X'; 
    Scanner scan =new Scanner(System.in); 


    String playerID(char player) 
    {  
     if (player == player1) 
      return "player1: "+player; 
     else 
      return "player2: "+ player; 
    } 

    void getPlayerInput(char player) 
    {  
     int row = 0; 
     int col = 0; 

     System.out.println(playerID(player) + ", it is your turn."); 
     System.out.println("Select a cell [a, b, c, ... i]"); 

     char answer; 
     answer = scan.next().charAt(0); 

     switch(answer) 
     { 
     case 'a': 
      row = 0; 
      col = 0; 
      break;   
     case 'b': 
      row = 0; 
      col = 1; 
      break;   
     case 'c': 
      row = 0; 
      col = 2; 
      break;   
     case 'd': 
      row = 1; 
      col = 0; 
      break;   
     case 'e': 
      row = 1; 
      col = 1; 
      break;   
     case 'f': 
      row = 1; 
      col = 2; 
      break; 
     case 'g': 
      row = 2; 
      col = 0; 
      break; 
     case 'h': 
      row = 2; 
      col = 1; 
      break; 
     case 'i': 
      row = 2; 
      col = 2; 
      break; 

     default: 
      System.out.println("Invalid location, try again."); 
      getPlayerInput(player);    
     } 

     if(ttt[row][col] != ' ') 
     { 
      System.out.println("This square is taken. Try again."); 
      getPlayerInput(player); 
     } 
     else 
     { 
      ttt[row][col] = player; 
     }    
    } 

    boolean gameIsDraw() 
    {  
     boolean isDraw = true; 
     for(int i = 0; i < 3; i++) 
     { 
      for(int j = 0; j < 3; j++) 
      { 
       if(ttt[i][j] == ' ') 
       { 
        isDraw = false; 
       } 
      } 
     } 

     return isDraw; 
    } 

    boolean winner(char player) 
    { 
     boolean hasWon = false; 

     // possible horizontal wins 
     for(int i = 0; i < 3; i++) 
     { 
      if(ttt[i][0] == player && ttt[i][1] == player && ttt[i][2] == player) 
      { 
       hasWon = true; 
      } 
     } 

     // possible vertical wins 
     for(int i = 0; i < 3; i++) 
     { 
      if(ttt[0][i] == player && ttt[1][i] == player && ttt[2][i] == player) 
      { 
       hasWon = true; 
      } 
     } 

     // one diagonal win  
     if(ttt[0][0] == player && ttt[1][1] == player && ttt[2][2] == player) 
     { 
      hasWon = true; 
     } 

     // other diagonal win 
     if(ttt[0][2] == player && ttt[1][1] == player && ttt[2][0] == player) 
     { 
      hasWon = true; 
     } 

     return hasWon; 
    } 


void displayBoard() 
    { 
     System.out.println("********************************");   
     System.out.println("  ---a------b------c---"); 

     for (int i=0; i<3; i++) 
     { 
      for (int j=0; j< 3; j++) 
      { 
       if (j == 0) System.out.print("  | "); 
       System.out.print(ttt[i][j]); 
       if (j < 2) System.out.print(" | "); 
       if (j==2) System.out.print(" |"); 
      } 
      System.out.println(); 
      switch (i) 
      { 
      case 0: 
       System.out.println("  ---d------e------f---"); 
       break; 
      case 1: 
       System.out.println("  ---g------h------i---"); 
       break; 
      case 2: 
       System.out.println("  ---------------------"); 
       break; 
      } 
     } 
    } 


void newgame() 
{ 
    char currPlayer = player1; 
    for(int i=0; i<3; i++) 
     for(int j=0; j<3; j++) 
      ttt[i][j] =' '; 

    boolean continueFlag = true;   
    while (continueFlag) 
    { 
     displayBoard(); 
     if (gameIsDraw()) 
     { 
      System.out.println("Game Ends in Draw"); 
      continueFlag = false; 
     } 
     else 
     { 
      getPlayerInput(currPlayer); 
      if (winner(currPlayer)) 
      { 
       System.out.println("We have a winner: " + playerID(currPlayer)); 
       displayBoard(); 
       continueFlag = false; 
      } 
      else 
      { 
       if (currPlayer == player1) currPlayer = player2; 
        else currPlayer = player1; 
      } 
     } 
    } 

} 


public static void main(String[] args) 
{ 
    TicTacToe game = new TicTacToe(); 
    String str; 
    do 
    { 
     game.newgame(); 

     System.out.println("Do you want to play Tic-Tac-Toe (y/n)?"); 
     str= game.scan.next(); 
    } while ("y".equals(str)); 

    System.out.println("Bye"); 
}  
} 

回答

1

真正的问题是,getPlayerInput被调用本身递归地。如果rowcolumn被初始化为错误值而不是实际值,则该问题将更加明显。 int row = -1;。递归通常适用于大问题,当分解为更小的相同问题时,可以更容易地处理这些问题。在这种情况下,问题就是获得一个有效的输入,这是一个无法分解为简单任务的任务。

而不是递归,该方法应该使用迭代进行输入验证。例如:

void getPlayerInput(char player) {  
    int row = -1; 
    int col = -1; 

    System.out.println(playerID(player) + ", it is your turn."); 

    while(row==-1) { 
     System.out.println("Select a cell [a, b, c, ... i]"); 

     char answer; 
     answer = scan.next().charAt(0); 

     switch(answer) { 
     case 'a': 
      row = 0; 
      col = 0; 
      break;   
     // <snip> 
     default: 
      System.out.println("Invalid location, try again."); 
     } 
     if(row !- -1 && ttt[row][col] != ' ') { 
      System.out.println("This square is taken. Try again."); 
      row = -1; 
     } 
    } 
    ttt[row][col] = player; 
} 
+0

谢谢你!除了你的帮助之外,我还睡在上面并且弄清楚了。我会提到,不幸的是,你的建议会导致运行时错误,因为如果输入错误输入,if语句会检查超出范围的位置,但这很容易通过另一个while循环进行修复。使用迭代而不是递归的关键思想我确定是主要观点。不过,如果你能解释为什么递归不是一个有效的策略吗? – HelloMyNameIsRay

+0

我尝试添加更多解释并修复代码。在任何情况下,RuntimeException正是你想要的!有些事情是错误的,它失败了。在原始代码中,由于行,列最初设置为0,0,所以错误的输入总是会导致尝试在0,0​​平方中播放。如果采用这个方块,递归调用会给用户另一次机会进行第二次递归调用(记住第一次发生在交换机的默认块中),基本上使用户获得的输入尝试次数加倍。 –