【问题标题】:c++ tic tac toe Non int characters causing infinite loopc ++ tic tac toe非int字符导致无限循环
【发布时间】:2020-07-12 17:08:49
【问题描述】:

尝试完成一个简单的井字游戏的作业,而不使用我们课堂上未涵盖的函数或任何东西。目前,代码中的所有内容都是可以接受的,但是在选择一个正方形并使用不是数字的字符时,我不断遇到无限循环问题。任何帮助将不胜感激!

#include <iostream>
using namespace std;

int i;
char board[10];
bool gameover;
bool check_choice;
char player;
int choice = 0;
char restart;

int main()
{

do
{


    for (int i = 0; i < 10; i++) board[i] = ' ';

    bool gameover = false;
    bool check_choice = true;
    char player = 'X';

    do
    {
        // Draw game board

        cout << "+---+---+---+ \n";
        cout << "| " << board[1] << " | " << board[2] << " | " << board[3] << " |  \n";
        cout << "+---+---+---+ \n";
        cout << "| " << board[4] << " | " << board[5] << " | " << board[6] << " |  \n";
        cout << "+---+---+---+ \n";
        cout << "| " << board[7] << " | " << board[8] << " | " << board[9] << " |  \n";
        cout << "+---+---+---+ \n";

        // Win Check

        if ((board[1] == 'X' && board[2] == 'X' && board[3] == 'X') ||
            (board[4] == 'X' && board[5] == 'X' && board[6] == 'X') ||
            (board[7] == 'X' && board[8] == 'X' && board[9] == 'X') ||
            (board[1] == 'X' && board[4] == 'X' && board[7] == 'X') ||
            (board[2] == 'X' && board[5] == 'X' && board[8] == 'X') ||
            (board[3] == 'X' && board[6] == 'X' && board[9] == 'X') ||
            (board[1] == 'X' && board[5] == 'X' && board[9] == 'X') ||
            (board[3] == 'X' && board[5] == 'X' && board[7] == 'X'))
        {
            cout << "Game Over - X wins! \n";
            gameover = true;
        }

        else if ((board[1] == 'O' && board[2] == 'O' && board[3] == 'O') ||
            (board[4] == 'O' && board[5] == 'O' && board[6] == 'O') ||
            (board[7] == 'O' && board[8] == 'O' && board[9] == 'O') ||
            (board[1] == 'O' && board[4] == 'O' && board[7] == 'O') ||
            (board[2] == 'O' && board[5] == 'O' && board[8] == 'O') ||
            (board[3] == 'O' && board[6] == 'O' && board[9] == 'O') ||
            (board[1] == 'O' && board[5] == 'O' && board[9] == 'O') ||
            (board[3] == 'O' && board[5] == 'O' && board[7] == 'O'))
        {
            cout << "Game Over - O wins! \n \n";
            gameover = true;
        }
        // Draw Check

        else if ((board[1] != ' ' && board[2] != ' ' && board[3] != ' ') &&
                 (board[4] != ' ' && board[5] != ' ' && board[6] != ' ') &&
                 (board[7] != ' ' && board[8] != ' ' && board[9] != ' '))
        {
            cout << "Game Over - Draw \n \n";
            gameover = true;
        }
        else

            check_choice = true;

        while (check_choice == true)
        {
            cout << "Place " << player << " at: ";
            cin >> choice;

            if (choice > sizeof(board) || choice == 0 || choice == 10)
            {
                cout << "Invalid input! 1-9 only. \n";
                check_choice = true;
            }

            else if (board[choice] == ' ')
            {
                board[choice] = (player == 'X') ? 'X' : 'O';
                player = (player == 'X') ? 'O' : 'X';
                check_choice = false;
            }
            else
            {
                cout << "Invalid input! Position already filled. \n";
                check_choice = true;
            }
        }

    } while (gameover == false);



    cout << "Would you like to play again? (Y / N): ";
    cin >> restart;
    cin.ignore();

} while (restart == 'y' || restart == 'Y');



cout << "Thanks for playing!! \n \n";

system("pause");
return 0;
} 

【问题讨论】:

  • 你的错误在哪里?
  • 数组从0开始索引,而不是1。您尝试通过1 访问board 可能会导致错误。
  • 但我在选择一个正方形并使用非数字字符时不断遇到无限循环问题。 -- 将您的数据读入字符串,并检查是否字符串具有有效信息。此外,您应该删除无关的全局变量,如果将其放入函数中而不是将所有内容都粘贴在 main 中,那将是一个更好的主意。
  • 如果你预计输入错误,你应该把输入变成一个字符串,检查字符串是否有有效的int数据,如果没问题就继续。还有一些建议——您可以将其缩减为“如何测试字符串是否为有效整数”或类似的东西,而不是发布整个井字游戏。显然会有 StackOverflow 的帖子介绍如何测试字符串是否为整数,您可以轻松搜索此类问题。
  • 有帮助的how to convert int to char, char to int after get an input 以及使用.ignore() 清除无效字符,请参阅How to catch invalid user inputs

标签: c++ loops while-loop nested-loops


【解决方案1】:

正如 melk 正确指出的那样,问题在于错误标志,当您输入错误时会设置错误标志,从而阻止您在清除标志之前使用流。

其他人建议使用字符串,然后验证输入,这会很好。但是,如果您不想对代码进行大量更改,您可以将 choice 变量声明为 char 类型。

现在,在您输入后,由于 char 数据类型的工作方式,您的选择变量将存储用户输入的字符的 ASCII 值。为了让它存储数值本身,你可以做这个巧妙的技巧:

choice -= '0';

这利用了这样一个事实,即在 ASCII 中,数字字符从'0' 开始一个接一个地出现。所以'1' - '0' 会给出1 而'5' - '0' 会给出5

现在您的其余代码运行良好,因为您不会遇到任何问题来检查输入的字符是否是 1-9 之间的数字。

虽然您还需要做的另一件事是在用户输入错误选择时刷新输入缓冲区。这是为了防止在用户输入多个字符时错误消息出现多次(每个输入一个字符一次)。

所以你的代码整体应该是这样的(我刚刚添加了两行):

#include <iostream>
using namespace std;

int i;
char board[10];
bool gameover;
bool check_choice;
char player;
char choice = 0; // the choice variable is now a character
char restart;

int main()
{

do
{


    for (int i = 0; i < 10; i++) board[i] = ' ';

    bool gameover = false;
    bool check_choice = true;
    char player = 'X';

    do
    {
        // Draw game board

        cout << "+---+---+---+ \n";
        cout << "| " << board[1] << " | " << board[2] << " | " << board[3] << " |  \n";
        cout << "+---+---+---+ \n";
        cout << "| " << board[4] << " | " << board[5] << " | " << board[6] << " |  \n";
        cout << "+---+---+---+ \n";
        cout << "| " << board[7] << " | " << board[8] << " | " << board[9] << " |  \n";
        cout << "+---+---+---+ \n";

        // Win Check

        if ((board[1] == 'X' && board[2] == 'X' && board[3] == 'X') ||
            (board[4] == 'X' && board[5] == 'X' && board[6] == 'X') ||
            (board[7] == 'X' && board[8] == 'X' && board[9] == 'X') ||
            (board[1] == 'X' && board[4] == 'X' && board[7] == 'X') ||
            (board[2] == 'X' && board[5] == 'X' && board[8] == 'X') ||
            (board[3] == 'X' && board[6] == 'X' && board[9] == 'X') ||
            (board[1] == 'X' && board[5] == 'X' && board[9] == 'X') ||
            (board[3] == 'X' && board[5] == 'X' && board[7] == 'X'))
        {
            cout << "Game Over - X wins! \n";
            gameover = true;
        }

        else if ((board[1] == 'O' && board[2] == 'O' && board[3] == 'O') ||
            (board[4] == 'O' && board[5] == 'O' && board[6] == 'O') ||
            (board[7] == 'O' && board[8] == 'O' && board[9] == 'O') ||
            (board[1] == 'O' && board[4] == 'O' && board[7] == 'O') ||
            (board[2] == 'O' && board[5] == 'O' && board[8] == 'O') ||
            (board[3] == 'O' && board[6] == 'O' && board[9] == 'O') ||
            (board[1] == 'O' && board[5] == 'O' && board[9] == 'O') ||
            (board[3] == 'O' && board[5] == 'O' && board[7] == 'O'))
        {
            cout << "Game Over - O wins! \n \n";
            gameover = true;
        }
        // Draw Check

        else if ((board[1] != ' ' && board[2] != ' ' && board[3] != ' ') &&
                 (board[4] != ' ' && board[5] != ' ' && board[6] != ' ') &&
                 (board[7] != ' ' && board[8] != ' ' && board[9] != ' '))
        {
            cout << "Game Over - Draw \n \n";
            gameover = true;
        }
        else

            check_choice = true;

        while (check_choice == true)
        {
            cout << "Place " << player << " at: ";
            cin >> choice;
            choice -= '0'; // added this line to convert character to number

            if (choice > sizeof(board) || choice == 0 || choice == 10)
            {
                cout << "Invalid input! 1-9 only." << std::endl;
                check_choice = true;
                fflush(stdin); // added this line to clear input buffer
            }

            else if (board[choice] == ' ')
            {
                board[choice] = (player == 'X') ? 'X' : 'O';
                player = (player == 'X') ? 'O' : 'X';
                check_choice = false;
            }
            else
            {
                cout << "Invalid input! Position already filled. \n";
                check_choice = true;
            }
        }

    } while (gameover == false);



    cout << "Would you like to play again? (Y / N): ";
    cin >> restart;
    cin.ignore();

} while (restart == 'y' || restart == 'Y');



cout << "Thanks for playing!! \n \n";

system("pause");
return 0;
}

顺便说一句,在游戏中做得很好。非常适合控制台项目。

【讨论】:

  • 您可能想补充一点,将选择读入char 仅适用于数字 0-9(如此处所示),只要它们更大(或更小),您将需要一个字符串。
【解决方案2】:

从流中读取时发生错误时,会设置错误标志,并且在清除错误标志之前无法进行更多读取。这就是你得到一个无限循环的原因。

here复制了答案,所以我不相信:P

正如@PaulMcKenzie 所说,您最好先将其读入字符串,然后进行必要的检查。

【讨论】:

    【解决方案3】:

    你可以使用类似的东西

    string mystr;
    getline (cin,mystr);
    

    将一行从 cin 读入一个字符串。之后,你可以检查它是否是一个数字,然后获取它,如果不是,则显示错误。

    PS:你不应该使用全局变量,你应该将你的代码拆分成函数。此外,您的数组比它需要的大一(您正在为 10 个元素分配空间,但您只需要 9 个)。请注意,因为您错误地从 1 开始索引,而当数组从 0 开始时,这意味着您现在完全忽略了第一个元素。如果您将其更改为分配 9 个元素,请确保将所有索引减 1 以使它们正确(否则访问 9 将导致错误,因为您正在访问数组边界之外的元素)。

    【讨论】:

    • 我猜他只是希望他的数组是 1-indexed,所以分配额外的空间。不是真正的问题。
    • 只是指出它比需要的大,并没有说这一定是个问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多