Sign in to follow this  
whitin

Difficulty Selection: Enhancements.

Recommended Posts

I made a simple random number game. At the beginning you can pick a difficulty which I though was a good way to practice switch statements. So, what I was wondering is that if there is an easier way to do this difficulty settings without having to put the whole while statement it seperate cases. Here is the code:
#include <cstdlib>
#include <iostream>
#include <ctime>

using namespace std;

int main()
{
  cout << "Welcome to the random number game. By: Austin Overton" << endl;
    cout << "Difficulty:\n\n";         //--- Start difficulty choosing
      cout << "1 = Easy Peasy (0-5)\n";
      cout << "2 = Normal Warmal(0-25)\n";
      cout << "3 = Crazy Insane(0-100)\n\n";

int choice;
  cout << "Choice: ";
  cin >> choice;             //---- End difficulty choosing

char again = 'y';          //--- restart define

switch (choice)
{
case 1:                      //---- Easy-----------
  while(again == 'y')
      {
int num1 = 0;

      srand(time(NULL));              //-----Rand-------
      int num2 = rand()%6;            //---Function------

        cout << "Please pick a number between 0 and 5." << endl;

        cout << "Number... ";
        cin >> num1;

      if (num1 != num2)
          {
          cout << "Sorry you lose. :( The correct number was " << num2 << endl << endl;
          cout << "Do you want to play again? (y/n): ";
          cin >> again;
          }
      else
          {
          cout << "Congratulations you guessed correctly!" << endl << endl;
          cout << "Do you want to play again? (y/n): ";
          cin >> again;
          }
}
    cout << "Ok, toddles!" << endl;
    break;
case 2:                   //-----Normal----------
  while(again == 'y')
      {
int num1 = 0;
                                          //------Rand------
      srand(time(NULL));                  //-----Function---
      int num2 = rand()%26;

        cout << "Please pick a number between 0 and 25." << endl;

        cout << "Number... ";
        cin >> num1;

      if (num1 != num2)
          {
          cout << "Sorry you lose. :( The correct number was " << num2 << endl << endl;
          cout << "Do you want to play again? (y/n): ";
          cin >> again;
          }
      else
          {
          cout << "Congratulations you guessed correctly!" << endl << endl;
          cout << "Do you want to play again? (y/n): ";
          cin >> again;
          }
}
    cout << "Ok, toddles!" << endl;
    break;
case 3:                        //------Hard------------
  while(again == 'y')
      {
int num1 = 0;

      srand(time(NULL));                      //----Rand-----
      int num2 = rand()%101;                  //---Function--

        cout << "Please pick a number between 0 and 100." << endl;

        cout << "Number... ";
        cin >> num1;

      if (num1 != num2)
          {
          cout << "Sorry you lose. :( The correct number was " << num2 << endl << endl;
          cout << "Do you want to play again? (y/n): ";
          cin >> again;
          }
      else
          {
          cout << "Congratulations you guessed correctly!" << endl << endl;
          cout << "Do you want to play again? (y/n): ";
          cin >> again;
          }
}
    cout << "Ok, toddles!" << endl;
    break;
default:
        cout << "Please pick legit choice." << endl;
}

    system("pause");
  return 0;
}



Is there a way to enhance this code so only the int num2 = rand()%6; code is the only thing that needs to go into the cases and have it be brought into the while statement after the switch? [Edited by - whitin on June 5, 2005 5:43:40 PM]

Share this post


Link to post
Share on other sites
Instead of having a huge switch statement (and duplicated code), you could just store the upper bound in a variable (depending on the difficulty selected) and just use that variable in the rest of the code:


#include <limits>

...

int choice = 0;
do
{
cout << "Choice: ";
cin >> choice;
if(cin.fail()) // not an int
{
cin.clear();
cin.ignore(numeric_limits<int>::max(),'\n');
}
} while(choice<1 || choice>3);

const int upper_bound_table[3] = { 6, 26, 101 };
int upper_bound = ubound_table[choice-1];

...

int num2 = rand() % upper_bound;

...

cout << "Please pick a number between 0 and " << upper_bound-1 << '.' << endl;

...



Oh, and break your code down into functions, PLEASE.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny

Oh, and break your code down into functions, PLEASE.


Well, I'm pretty new to programming and I am going along with a book "Beginning C++ Game Programming" and we hav'nt gotten to functions yet. I am just getting everything down and secure before I move on.

Share this post


Link to post
Share on other sites
I would like to highlight the useful techniques involved here.


int choice = 0;
do
{
cout << "Choice: ";
cin >> choice;
if(cin.fail()) // not an int
{
cin.clear();
cin.ignore(numeric_limits<int>::max(),'\n');
}
} while(choice<1 || choice>3);


Robust reading of an integer value. If the user types in some non-numeric value, the stream (cin in this case) gets put into a "fail" state; until that is reset, no more reading is possible, and the garbage value is still treated as being "about to be read". The clear() call resets the stream, and the ignore() call skips the current line of input (the numeric_limits thing comes from the included limits header, and is basically just a really big number - this is a workaround for a quirk in the design of ignore()). This handling is especially important inside a loop; otherwise you can easily get an infinite loop.


const int upper_bound_table[3] = { 6, 26, 101 };
int upper_bound = ubound_table[choice-1];


A look-up table is used, instead of a switch statement. This is one good example of doing things in data instead of code. Anywhere that the code would be repetitive, it's a good idea to look for this kind of thing instead - it's simpler.

Also note that the array indexes start at 0. Do not try to "fight" this; instead, use 0-based values internally, and only convert back and forth to 1-based values when you need to communicate with the user. Here, 1 is subtracted from the user's input right at the point where an array index is needed.


int num2 = rand() % upper_bound;


The variable contents are used in the random number selection. This is the key idea you were looking for, of course.

cout << "Please pick a number between 0 and " << upper_bound-1 << '.' << endl;


Again, conversion is done at the time of communicating to the user. Since upper_bound is one more than the highest possible value, we subtract 1 when outputting.




As for functions, you certainly have gotten to them; they just haven't been explained yet. main() is a function. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
I would like to highlight the useful techniques involved here.


int choice = 0;
do
{
cout << "Choice: ";
cin >> choice;
if(cin.fail()) // not an int
{
cin.clear();
cin.ignore(numeric_limits<int>::max(),'\n');
}
} while(choice<1 || choice>3);



I'm curious, when faced with this problem in a programming class, I came up with the idea of using cin.sync() instead of cin.ignore() because of the design quirk you mentioned. After I asked my TAs about it, they started suggesting to other students that they do it my way. Is there any reason that ignore should be preferred here?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this