如何在我的c版本Tic-Tac-Toe中修复我的输入验证

How to fix my input validation in my c version of Tic Tac Toe?

本文关键字:我的 输入 验证 版本 Tic-Tac-Toe      更新时间:2023-10-16

我正在使用基于控制台的界面在C中创建一个Tic-Tac-Toe游戏。两个玩家通过从1-9中选择一个数字将他们的棋子放在棋盘上来对抗对方(例如,如果你输入一个,那么它会将你的棋子放置在左上角,输入两个会将其放置在中上角,键入三个会将它放在右上角,依此类推)。然而,我的代码的主要问题是,每当有人输入一个字母时,游戏基本上都会陷入一个永恒的循环,直到你关闭程序,我尝试了很多解决方案(比如使用开关盒,将输入变成一个字符等),但我不知道如何解决它。谢谢。

//Libaries
#include <iostream>
#include <string>
#include <array>
using namespace std;
//Indentifers
void gamescreen(); //Used to display the board
char gamecondition(); //This is indentifer is used to check the game is won lost/draw
void playerturn();
void playernames();
int resultsscreen();
int turn;
int playerinput(int playerchoice);
int Player1Score, Player2Score;
//Variables
//int menuchoice; //Not Neeeded for now
char PlayerPiece = 'X';
char GameWinner;
char board[3][3] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; //Creates a 3 by 3 matrix, which is basically the board.
int playerchoice; //Reason why playerchoice is a int rather than a char is because
string Player1Name, Player2Name;
char finalchoice;
void playernames()
{
    cout << "Player 1 please enter your name" << endl; //Asks for the first username
    cin >> Player1Name; // Gets the first user name
    cout << "Player 2 please enter your name" << endl; //Asks for the second username
    cin >> Player2Name; // Gets the second user name
    cout << "Player 1 Name is: " << Player1Name << " " << "and Player 2 name is: " << Player2Name << endl; //Displays Usernames
}
void gamescreen() //Displays the board on the screen to the players
{
    system("cls"); //CLears the screen again, to make the game clean and tidy
    cout << "SCOREBOARD: " << Player1Name << ": " << Player1Score << " " << Player2Name << ": " << Player2Score << endl;
    cout << "n" << endl;
    cout << board[0][0] << " | " << board[0][1] << " | " << board[0][2] << endl;
    cout << board[1][0] << " | " << board[1][1] << " | " << board[1][2] << endl;
    cout << board[2][0] << " | " << board[2][1] << " | " << board[2][2] << endl;
}
void playercheck()
{
    cout << "It is Player: " << PlayerPiece << " Turn, please put select a piece on the board" << endl;
    cin >> playerchoice;
    playerinput(playerchoice);
}
int playerinput(int playerchoice)
{
    if (playerchoice > 9 || playerchoice < 1 || cin.fail())
    {
        cout << "Please enter a number from 1-9!" << endl;
        cin.clear();
        playercheck();
    }
    else
    {
        if (playerchoice == 1) //If the player chose this one then
        {
            if (board[0][0] == '1') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[0][0] = PlayerPiece; //If the condition is true, then it replaces that board space with the player piece
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 2) //If the player chose this one then
        {
            if (board[0][1] == '2') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[0][1] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 3) //If the player chose this one then
        {
            if (board[0][2] == '3') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[0][2] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 4) //If the player chose this one then
        {
            if (board[1][0] == '4') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[1][0] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 5) //If the player chose this one then
        {
            if (board[1][1] == '5') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[1][1] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 6) //If the player chose this one then
        {
            if (board[1][2] == '6') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[1][2] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 7) //If the player chose this one then
        {
            if (board[2][0] == '7') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[2][0] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 8) //If the player chose this one then
        {
            if (board[2][1] == '8') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[2][1] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else if (playerchoice == 9) //If the player chose this one then
        {
            if (board[2][2] == '9') //This turns the number into a position on the board, it checks if the place is valid and there isn't a position on the board. If so then it places the player piece down
                board[2][2] = PlayerPiece;
            else
            {
                cout << "This move is invalid because this space has been claimed" << endl; //However if there was not a space or the player just decides to put a number other than 1-9 then this message pops up
                playercheck(); //This function is called again to elimate the need for loops.
            }
        }
        else
        {
            cout << "Please enter in a valid number!" << endl;
            playercheck();
            //Fail safe just in case the first one failed somehow.
        }
    }
    //The if statements about choices, etc. Checking if this space has not been picked yet
    //NEED TO CHANGE ALL OF THE NUMBERS
    return 1;
}
void playerturn()
{
    if (PlayerPiece == 'X')
        PlayerPiece = 'O';
    else
        PlayerPiece = 'X';
}
char gamecondition() //This is used to check the win conidtion aka who won or if not how does this game draw?
{
    //Checks for the first player
    if (board[0][0] == 'X' && board[0][1] == 'X' && board[0][2] == 'X')
        return 'X'; //Basically this checks if the there is three in a row in the board, if show it returns the value X, which will be shown in the main. (Basically if GameWinner == X, cout << "Player1 wins!" << endl;
    if (board[1][0] == 'X' && board[1][1] == 'X' && board[1][2] == 'X')
        return 'X';
    if (board[2][0] == 'X' && board[2][1] == 'X' && board[2][2] == 'X')
        return 'X';
    if (board[0][0] == 'X' && board[1][0] == 'X' && board[2][0] == 'X')
        return 'X';
    if (board[0][1] == 'X' && board[1][1] == 'X' && board[2][1] == 'X')
        return 'X';
    if (board[0][2] == 'X' && board[1][2] == 'X' && board[2][2] == 'X')
        return 'X';
    if (board[0][0] == 'X' && board[1][1] == 'X' && board[2][2] == 'X')
        return 'X';
    if (board[2][0] == 'X' && board[1][1] == 'X' && board[0][2] == 'X')
        return 'X'; //Returns X to the gamecondition()
                    //Checks for the second player
    if (board[0][0] == 'O' && board[0][1] == 'O' && board[0][2] == 'O')
        return 'O'; //Basically this checks if the there is three in a row in the board, if show it returns the value X, which will be shown in the main. (Basically if gameconidition == X, cout << "Player1 wins!" << endl;
    if (board[1][0] == 'O' && board[1][1] == 'O' && board[1][2] == 'O')
        return 'O';
    if (board[2][0] == 'O' && board[2][1] == 'O' && board[2][2] == 'O')
        return 'O';
    if (board[0][0] == 'O' && board[1][0] == 'O' && board[2][0] == 'O')
        return 'O';
    if (board[0][1] == 'O' && board[1][1] == 'O' && board[2][1] == 'O')
        return 'O';
    if (board[0][2] == 'O' && board[1][2] == 'O' && board[2][2] == 'O')
        return 'O';
    if (board[0][0] == 'O' && board[1][1] == 'O' && board[2][2] == 'O')
        return 'O';
    if (board[2][0] == 'O' && board[1][1] == 'O' && board[0][2] == 'O')
        return 'O';
    else
        return '/'; //If it isn't either O or X then returns '/' which shows it's a draw
}

int main()
{
    playernames();
    turn = 0; //This is a turn counter, this will be used to determine the draw (Without it the game will keep on going)
    gamescreen(); //Displays the game screen again
    while (1)
    {
        turn++; //If the game hasn't been completed yet then adds 1 to the number counter
        playercheck();
        gamescreen();
        if (gamecondition() == 'X')
        {
            cout << Player1Name << "X wins!" << endl;
            Player1Score++;
            resultsscreen();
        }
        else if (gamecondition() == 'O')
        {
            cout << Player2Name << " wins!" << endl;
            Player2Score++;
            resultsscreen();
        }
        else if (gamecondition() == '/' && turn == 9)
        {
            cout << "It's a draw!" << endl;
            resultsscreen();
        }
        playerturn();
    }
}
int resultsscreen()
{
    cout << "The current score is:" << endl;
    cout << Player1Name << ":" << Player1Score << endl;
    cout << Player2Name << ":" << Player2Score << endl;
    cout << "Would you like to play again, Y/N?" << endl;
    cin >> finalchoice;
    if (finalchoice == 'Y' || finalchoice == 'y')
    {
        turn = 0;
        board[0][0] = '1', board[0][1] = '2', board[0][2] = '3';
        board[1][0] = '4', board[1][1] = '5', board[1][2] = '6';
        board[2][0] = '7', board[2][1] = '8', board[2][2] = '9';
        system("cls");
        gamescreen();
        playercheck();
        playerturn();
        playerinput(playerchoice);
    }
    if (finalchoice == 'N' || finalchoice == 'n')
    {
        if (Player1Score > Player2Score)
        {
            cout << Player1Name << " wins!" << endl;
            system("pause");
            exit(0);
        }
        if (Player1Score < Player2Score)
        {
            cout << Player2Name << " wins!" << endl;
            system("pause");
            exit(0);
        }
        else if (Player1Score == Player2Score)
        {
            cout << "It's a draw!" << endl;
            system("pause");
            exit(0);
        }
    }
    return 0;
}

当用户输入错误时,您需要做两件事:

  1. 清除程序中输入流的状态
  2. 忽略行的其余部分,因为您没有这些内容

您需要的是:

if (playerchoice > 9 || playerchoice < 1 || cin.fail())
{
    cin.clear();
    cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
    cout << "Please enter a number from 1-9!" << endl;
    playercheck();
}

确保添加

#include <limits>

以便能够使用CCD_ 1。

有一种方法可以应用于cin,称为fail(),它是:

  • 如果变量的输入与该变量的类型相同,则返回true
  • 如果变量的输入与该变量的类型不同,则返回false

因此,在playercheck()函数中,接受输入,playerchoice被定义为类型int

void playercheck()
{
    cout << "It is Player: " << PlayerPiece << " Turn, please put select a piece on the board" << endl;
    cin >> playerchoice;
    playerinput(playerchoice);
}

在上面添加一个while循环,重复检查是否有整数和数字1-9,直到得到适当的响应。

void playercheck()
{
    cout << "It is Player: " << PlayerPiece << " Turn, please put select a piece on the board" << endl;
    cin >> playerchoice;
    //while the input it less than 1, more than 9, or NOT an integer
    while (playerchoice < 1 || playerchoice > 9 || cin.fail()) 
    {
       cout << "You did not enter an appropriate response." << endl;
       cout << "Please, enter in a digit between 1 and 9." << endl;

       //clear the input flag on the stream so we can recheck cin.fail()
       cin.clear();
       //skip up to 256 characters in the pursuit of skipping to the next newline
       cin.ignore(256, 'n');
       cin >> playerchoice;
    }
    playerinput(playerchoice);
}