Hi everybody,
I’m having trouble trying to figure out how to create a loop when the ‘difficulty’ takes a value that is not an integer. I want a player to get the ‘default’ statement presented in the switch . The ‘default’ statement seems to make an appearance but it will not execute the ‘cin >> difficulty’ when ‘cin >> difficulty’ equals anything but an int. I tried using the ‘cin.ignore(difficulty);’ but it doesn’t appear to work. I’m I not using it properly?
I’m just learning how to program so I lack plenty of experience.
Here is the code:

#include <iostream>
#include <string>

using namespace std;

int main()


        {


    cout << "Welcome to 'CAN YOU GUESS MY NUMBER'\n" <<endl;
    cout << "Choose your difficulty: \n" <<endl;

    cout << "1: Easy" <<endl;
    cout << "2: Normal" <<endl;
    cout << "3: Hard\n" <<endl;

    //Difficulty loop

    int difficulty;
    cin >> difficulty;

    bool pass1 = true;

    switch (difficulty)
    {
    case 1:
        cout << "You will play the game in easy\n" << endl;
        pass1 == true;
        break;
    case 2:
        cout << "You will play the game in Normal difficulty\n" << endl;
        pass1 == true;
        break;
    case 3:
        cout << "You will play the game in Hard\n" << endl;
        pass1 == true;
        break;
    default:
        cout << "You have made an invalid choice." << endl;
        cout << "Choose a difficulty level: \n" << endl;
        cout << "'1' for Easy" << endl;
        cout << "'2' for Normal" << endl;
        cout << "'3' for Hard\n\n" << endl;

        cin.ignore(difficulty);

        cin >> difficulty;
        pass1 == false;

    } while (!pass1);

    // Easy loop

    // Normal loop

    // Hard loop

    return 0;
    }

Edited 3 Years Ago by Dani: Formatting fixed

Not sure exactly what was causing the problem. But caling it again in the default case is redundant. Encasing the switch block in a while loop and only calling cin once per loop will solve the problem. Something like this:

#include <iostream>
using namespace std;
int main()

{
    int difficulty;
    bool pass1 = false;
    cout << "Welcome to 'CAN YOU GUESS MY NUMBER'\n" <<endl;
    while(!pass1)
    {
        cout << "Choose your difficulty: \n" <<endl;
        cout << "1: Easy" <<endl;
        cout << "2: Normal" <<endl;
        cout << "3: Hard\n" <<endl;
        cin >> difficulty;
        switch (difficulty)
        {
        case 1:
            cout << "You will play the game in easy\n" << endl;
            pass1 = true;
            break;
        case 2:
            cout << "You will play the game in Normal difficulty\n" << endl;
            pass1 = true;
            break;
        case 3:
            cout << "You will play the game in Hard\n" << endl;
            pass1 = true;
            break;
        default:
            cout << "\nYou have made an invalid choice." << endl;

        }
    }
    return 0;
}

Notice how using the Code option in the editor allows all your code to be displayed as code.

Edited 3 Years Ago by tinstaafl

Here is a shell that shows one popular student way to start a menu / choice / switch type program.

Note the use of functions to facilitate your logic flow and code developement testing steps.

Note the use of getline for input so that the WHOLE line is input.

#include <iostream>
#include <string>

using namespace std;


void lev1( )
{
    cout << "\n\nLevel 'Easy' is being developed ...\n";
}
void lev2( )
{
    cout << "\n\nLevel 'Normal' is being developed ...\n";
}
void lev3( )
{
    cout << "\n\nLevel 'Hard' is being developed ...\n";
}

int showMenuGetChoice()
{
    cout << "\nWelcome to 'CAN YOU GUESS MY NUMBER?'\n\n"
         << "Choose your difficulty: \n"
         << "1: Easy\n"
         << "2: Normal\n"
         << "3: Hard\n"
         << "0: Quit\n"
         << "Enter your choice 0..3 : " << flush;
    string line;
    getline( cin, line );
    if( line.size( ) != 0 ) return line[0];
    // else ...
    return 0;
}

void pauseForEnter()
{
    cout << "\nPress 'Enter' to continue ... " << flush;
    string line;
    getline( cin, line );
}


int main()
{
    bool done = false;
    do
    {
        switch( showMenuGetChoice() )
        {
            case '1' : lev1(); break;
            case '2' : lev2(); break;
            case '3' : lev3(); break;
            case '0' : done = true; break;
            default: cout << "\n\nYou have made an invalid choice.\n";
        }
    }
    while( !done );

    pauseForEnter();

}

@tinstaafl: your method is a lot more organize and logic is clearer, but I still get an infinite loop when the input for ‘difficulty ‘ is not an integer. I’m trying how to figure out how to ignore or make that last input clear or ignore the ‘difficult’ input when given a value so the loop doesn’t become infite.

#include <iostream>
using namespace std;
int main()

    //Difficulty Loop
    //infinite loop error.
{
    int difficulty;
    bool pass1 = false;
    cout << "Welcome to 'CAN YOU GUESS MY NUMBER'\n" <<endl;
    while(!pass1)
    {
        cout << "Choose your difficulty: \n" <<endl;

        cout << "1: Easy" <<endl;
        cout << "2: Normal" <<endl;
        cout << "3: Hard" <<endl;
        cout << "0: Quit\n" <<endl;

        cout << "Enter your choice: 0-3:\n"<< endl;

        cin >> difficulty;
        switch (difficulty)
        {
        case 0: 
            cout << "Thank you for playing.\n" << endl;
            pass1=true;
            break;
        case 1:
            cout << "You will play the game in easy\n" << endl;
            pass1 = true;
            break;
        case 2:
            cout << "You will play the game in Normal difficulty\n" << endl;
            pass1 = true;
            break;
        case 3:
            cout << "You will play the game in Hard\n" << endl;
            pass1 = true;
            break;
        default:
            cout << "\nYou have made an invalid choice." << endl;
            pass1=false;
            break;
        }
    }
    return 0;
}

Consider this simple example of clearing the input line on an invalid conversion:

#include <ios>
#include <iostream>
#include <limits>

using namespace std;

int main()
{
    int num;

    while (true)
    {
        cout << "Enter a number: ";

        if (cin >> num)
        {
            break;
        }

        cerr << "Invalid input\n";

        // Clear the stream state so we can read again
        cin.clear();

        // Extract everything remaining on the line
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }

    cout << "You entered " << num << '\n';
}

When a conversion by the >> operator fails, it puts cin into an error state where it won't read anymore data. Also, the bad data is left on the stream. So you need to clear the error state and then discard the bad data before trying again.

Sorry forgot you were using int. By changing difficulty to char and modifying the switch block to check for char cin doesn't enter an error state and the loop acts normally:

    switch (difficulty)
    {
    case '0':
        cout << "Thank you for playing.\n" << endl;
        pass1=true;
        break;        
    case '1':
        cout << "You will play the game in easy\n" << endl;
        pass1 = true;
        break;
    case '2':
        cout << "You will play the game in Normal difficulty\n" << endl;
        pass1 = true;
        break;
    case '3':
        cout << "You will play the game in Hard\n" << endl;
        pass1 = true;
        break;
    default:
        cout << "\nYou have made an invalid choice." << endl;
    }

Edited 3 Years Ago by tinstaafl

He said,

but I still get an infinite loop when the input for ‘difficulty ‘ is not an integer.

Meaning he intends for the loop to end when difficulty is not an integer.

You seem to be experiencing a very common 'beginner design problem' ... due to a lack of understanding about how cin (stream input) works ... especially when numeric input is expected ... and what then happens when cin enters a 'failed' state.

cin skips over all leading ws (white space) char's and tests the first non-ws char to see if it is of the type expected.

For example:

If an int (type) was being expected, and the 1st non-ws char is a + or - sign or a digit in the range 0..9 ... all is still ok ... and cin will keep taking in valid digits, from the cin stream, until it reaches a non-valid-digit-including-a-ws ( ws includes ' ', '\t', '\n' )

If the integer taken in was within the size limits for an int, no error flags are set ... all is 'good'

Other-wise ... a cin error flag is set and cin enters into a 'failed state' ... and stays in that failed state and will not accept any more input until 'cleared' via cin.clear() ... so any char's that were entered after the failed char and before the 'Enter' key was pressed will still be there in the cin stream

This following little demo may give you some more ideas about ways to deal with cin (single number) input.

// cinErrorDemo.cpp //

#include <iostream>


using namespace std;


char getCharReply( const std::string& msg )
{
    std::cout << msg << std::flush;
    std::string reply;
    getline( std::cin, reply );
    if( reply.size() ) return reply[0];
    // else ...
    return 0;
}

bool more()
{
    if( tolower( getCharReply( "\nMore (y/n) ? " )) == 'n' ) return false;
    // else ...
    return true;
}


// prompt and take in and return a valid int
// default prompt is ""
int takeInValidInt( const std::string& prompt = "" ) 
{
    int val;
    while( true )
    {
        std::cout << prompt << std::flush;
        if( std::cin >> val )
        {
            if( std::cin.get() == '\n' )
                break; // break out of while loop right NOW
            // else
            std::cout << "\nThere were extra char's entered ...\n";
        }
        else
        {
            if( !std::cin.good() ) std::cout << "good is not true ...\n";
            if( std::cin.fail() ) std::cout << "fail is true ...\n";

            std::cin.clear(); // clear flags ...
        }
        std::cin.sync(); // 'flush' cin stream...
        std::cout << "Try again ...";
    }
    return val;
}



int main()
{
    do
    {
        int myInt = takeInValidInt( "Enter an integer: " );
        cout << "You entered " << myInt << "\n";
    }
    while( more() );
}

Note that taking in 'line input' via C++ getline and C++ string ...
then parsing that line (that string ...perhaps using stringstream) ...
can also be useful to avoid input loops crashing on bad input ...
and also avoids the problem of 'dangling left over chararacters'

Note that char input will NOT crash because of bad input as per this updated example:

// getline.cpp //

#include <iostream>
#include <string>

using namespace std;


void lev1()
{
    cout << "\n\n'Easy' is being developed ...\n";
}
void lev2()
{
    cout << "\n\nNormal' is being developed ...\n";
}
void lev3()
{
    cout << "\n\n'Hard' is being developed ...\n";
}

int showMenuGetChoice()
{
    cout << "\nWelcome to 'CAN YOU GUESS MY NUMBER?'\n\n"
         << "Choose your difficulty: \n"
         << "1: (E)asy\n"
         << "2: (N)ormal\n"
         << "3: (H)ard\n"
         << "0: (Q)uit\n"
         << "Enter your choice 0..3 or e..q: " << flush;
    string line;
    getline( cin, line );
    if( line.size() != 0 ) return line[0];
    // else ...
    return 0;
}

void pauseForEnter()
{
    cout << "\nPress 'Enter' to continue ... " << flush;
    string line;
    getline( cin, line );
}


int main()
{
    bool done = false;
    do
    {
        switch( showMenuGetChoice() )
        {
            case '1' : case 'e' : case 'E' : lev1(); break;
            case '2' : case 'n' : case 'N' : lev2(); break;
            case '3' : case 'h' : case 'H' : lev3(); break;
            case '0' : case 'q' : case 'Q' : done = true; break;
            default: cout << "\n\nInvalid choice ... try again.\n";
        }
    }
    while( !done );

    pauseForEnter();
}

Note:

some times you want cin to take in several numbers on a line ...

or from a file, right up to the end of that file ...

so this above single number input code, to take in a single valid number from a user via keyboard, would not apply there.

This question has already been answered. Start a new discussion instead.