1

I am struggling to get an input validation working for my game.

#include <iostream>
#include <ctime>
using namespace std;

int main()
{

    int iGumballs;
    int iUserguess;
    int iGuesses = 0;

    while (true)
    {
        system("CLS");
        cin.clear();
        iGuesses = 0;

    srand(static_cast<unsigned int>(time(0)));
    iGumballs = rand()%1000+1;
    cout << "How many gumballs are in the bumball jar? You guess! 1-1000" << endl;

    do
    {
        cout << "Enter your guess: ";


    cin >> iUserguess;


    if(iUserguess > iGumballs)
    {
        cout << "Too high!" << endl << endl;
    }

    if(iUserguess < iGumballs)
    {
        cout << "Too low!" << endl << endl;
    }
    iGuesses ++;
    }
    while(iUserguess > iGumballs || iUserguess < iGumballs);
    cout << "You guessed the right amout of gumballs" << endl << endl;
    cout << "You took " << iGuesses << " guesses" << endl << endl;
    system ("pause");
    }
    return 0;
}

I basically want the program to display

Your Guess: Sorry, incorrect input - try again

When the user enters a number less then 1, and higher then 1000, as well as some sort of validation which makes sure a number is entered instead of a letter or symbol. I tried cin.fail() but I couldn't get it quite to work.

Thanks, John

John Brown
  • 151
  • 3
  • 14

3 Answers3

2

You will need some test to see if is a number or not, try this:

#include <iostream>
#include <string>
#include <ctime>
#include <boost/lexical_cast.hpp> //dependency that can be optional
using namespace std;

bool is_number(const std::string& s)
{
    std::string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

int main()
{

    int iGumballs;
    std::string iUserguessStr;
    int iUserguess;
    int iGuesses = 0;

    while (true)
    {
        system("CLS");
        cin.clear();
        iGuesses = 0;

    srand(static_cast<unsigned int>(time(0)));
    iGumballs = rand()%1000+1;
    cout << "How many gumballs are in the bumball jar? You guess! 1-1000" << endl;

    do
    {
        cout << "Enter your guess: ";


    cin >> iUserguessStr;
    if(is_number(iUserguessStr))
        iUserguess = boost::lexical_cast<int>(iUserguessStr); //you can make your own or maybe use lexical cast to transform a string into integer
    else
        continue; //put some fancy message here warning the user


    if(iUserguess > iGumballs)
    {
        cout << "Too high!" << endl << endl;
    }

    if(iUserguess < iGumballs)
    {
        cout << "Too low!" << endl << endl;
    }
    iGuesses ++;
    }
    while(iUserguess > iGumballs || iUserguess < iGumballs);
    cout << "You guessed the right amout of gumballs" << endl << endl;
    cout << "You took " << iGuesses << " guesses" << endl << endl;
    system ("pause");
    }
    return 0;
}

My answer is based on a related problem: How to determine if a string is a number with C++?

Community
  • 1
  • 1
coelhudo
  • 4,162
  • 7
  • 35
  • 53
  • I'll download the boost repositry tomorrow and see how yours works out. – John Brown Jan 05 '13 at 00:23
  • With boost it is safe to detect an error on conversion (catching boost::bad_casting exception), but you can try the function from the standard for conversion between c-string and integer called std::atoi (http://en.cppreference.com/w/cpp/string/byte/atoi) – coelhudo Jan 05 '13 at 12:03
1

Yo can use if(cin) to check the state of the input stream and since operator>> will return the input stream that was passed to it you can use if(cin>>iUserguess)

If cin is in a failed state -maybe because the user entered a non number- the expression if(cin>>iUserguess) will evaluate to false.

If the user enters a non number you will need to call cin.clear() to clear the stream state and cin.ignore() to discard the input, before trying to read a number again.

so using your example, it could be changed to this:

#include <iostream>
#include <ctime>
#include <limits>
using namespace std;

int main()
{

    int iGumballs;
    int iUserguess;
    int iGuesses = 0;

    while (true)
    {
        system("CLS");

        iGuesses = 0;

        srand(static_cast<unsigned int>(time(0)));
        iGumballs = rand()%1000+1;
        cout << "How many gumballs are in the bumball jar? You guess! 1-1000" << endl;

        do
        {
            cout << "Enter your guess: ";
            if(cin >> iUserguess)
            {
                iGuesses ++;
                if(iUserguess > iGumballs)
                {
                    cout << "Too high!" << endl << endl;
                    continue;
                }

                if(iUserguess < iGumballs)
                {
                    cout << "Too low!" << endl << endl;
                    continue;
                }
            }
            else
            {
                cout<<"incorrect input - try again\n\n";
                cin.clear();
                cin.ignore(numeric_limits<streamsize>::max(),'\n');
                continue;
            }
        }
        while(iUserguess > iGumballs || iUserguess < iGumballs);
        cout << "You guessed the right amout of gumballs" << endl << endl;
        cout << "You took " << iGuesses << " guesses" << endl << endl;
        system ("pause");
    }
    return 0;
}
coelhudo
  • 4,162
  • 7
  • 35
  • 53
1

To validate characters you could use the try-catch structure.

-First read in a string and try Typecasting it and handle the errors with try-catch.
-Then use conditions to make sure the input is in range.
-If the input isn't valid, you can write an error message to display.

David Tóth
  • 1,479
  • 11
  • 32
  • It's usually not a good idea to use try-catch to control the flow of a program. try-catch is for exception handling. Exception handling is pretty slow. It's not wrong to use exceptions, but check for errors manually first. Don't throw unneccessary exceptions. – Skalli Jan 07 '13 at 12:48