【问题标题】:Semantic Error in basic Tictactoe program in JavaJava中基本Tictactoe程序中的语义错误
【发布时间】:2013-08-04 05:14:33
【问题描述】:

首先,我希望我可以在这里寻求一些调试帮助。照这样说, 我已经创建了这个简单的小井字游戏,基本上已经完成了,但是这个语义错误一直在杀死我。

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

对于一些简要概述,板由 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] 被初始化,使得每个元素都只是 ' '。

在大多数情况下,程序运行良好。为了尽量为你们节省一些时间,我相信以下方法运行良好

  • 布尔获胜者(字符播放器)
  • 布尔游戏IsDraw()
  • void displayBoard()
  • 字符串播放器ID(字符播放器)
  • 及主要方法

我确实看到的问题很可能包含在我的 getPlayerInput(char 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;
    }            
}

对我来说,它看起来不错,但我的输出表明并非如此。该方法包括两个故障保护,

  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”,显然是一个有效的位置,但是该方法打印出“正方形已经被占用”,而显然不是。但是,输入不同的字符“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");
}    
} 

【问题讨论】:

    标签: java semantics tic-tac-toe


    【解决方案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;
    }
    

    【讨论】:

    • 谢谢你!除了你的帮助,我睡在上面并想通了。我会提到,不幸的是,您的建议会导致运行时错误,因为如果输入了错误的输入,if 语句会检查越界位置,但这很容易通过另一个 while 循环来解决。我敢肯定,使用迭代而不是递归的关键思想是重点。不过,如果你能解释一下为什么递归在这里不是一个有效的策略,是否有可能?
    • 我尝试添加更多解释并修复代码。无论如何,RuntimeException 正是您想要的!出了点问题,它失败了。在原始代码中,由于 row,column 最初设置为 0,0,错误的输入总是会导致尝试在 0,0 方格中播放。如果采用该方块,则递归调用将为用户提供第二次递归调用的第二次机会(记住第一次发生在 switch 的默认块中),基本上使用户获得的输入尝试加倍。
    猜你喜欢
    • 1970-01-01
    • 2014-09-07
    • 2023-04-09
    • 1970-01-01
    • 2015-09-13
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 2012-03-27
    相关资源
    最近更新 更多