CSCI 261 Programming Concepts (C++)

Winter/Spring 2012

Lab 4: Number Guessing Game

Concepts

This assignment excercises your ability to use loops and shows you how to ask the computer to generate a pseudo-random number.

Loop Patterns

Let's face it: you should eat mindfully. But if you've ever visited any number of fast-food burger places, you'll probably notice something: they all share a similar "pattern." You go inside, walk up to the counter, order what you want, pay, receive your "food," eat it, belch a little, and then you leave. They're all pretty much the same, yes?

Over time, you will notice that there are some frequently-occuring use cases for loops. You might use a loop to capture user input; or you might use a loop to do something N times; or you might want to use an infinite loop that you'll break out of when a condition is met. We call these "loop patterns," and want you to recognize them. More importantly, when given an idea that you must implement as code, we want you to be able to quickly realize, "Aha, that sounds like I can use ______ kind of loop."

Sentinel Loop

This is typically a while loop that repeats until the condition is met. One common example of this is capturing specific user input. Here's an example:

string input;
const string END = "end";
while ( input != END) {
    cout << "Please make it stop!\n";
    cin >> input;
}

Each repetition of the loop provides a chance to end the loop. The condition acts as a "sentinel" or "guard" that makes sure the loop repeats until that "sentienl" allows the loop to end.

Counted Loops

This is typically a for loop that uses some kind of counter variable to accomplish a repetitious task. You'll probably recognize this pattern immediately:

for (int i = 4; i > 0; i--) {
    cout << i << " and ";
}
cout << "when I'm on the mic the suckas run"

Each repetition of the loop does something a little different depending on what the counter, i is during that round of repetition. (Forgive the Beastie Boys lyric.)

Extra-Conditional Loops

We're going to call these "extra-conditional" because these loops usually have a primary condition used in the loop predicate yet have an extra condition that is used inside the loop that causes a possible break. Here is an example:

int input;
const int QUIT = 0;

while ( input >= 0 && input < 10 ) {
    cout << "Enter a number between 1 and 10 (or 0 to quit): ";
    cin >> input;
    if (input == QUIT) break;
}

Do you see how the main loop will repeat as long as the user enters a number between 0 and 10, but breaks out of the loop when the input is 0?

End-of-Data Loops

You don't have to memorize this yet, but we'll see this pattern next week when we discuss I/O. Sometimes you want to coninuously read data from an input stream (a stream of data) until you get to the end of that data. They usually look something like this:

while ( there_is_more_data_to_read ) {
    // read the next piece of data
}

Just be aware of this pattern; you'll see it again soon.

Pseudo-Random Numbers

You should have been briefly introduced to your new friends srand() and rand() in lecture, and been informed about how true randomness is something difficult for a machine to simulate. But is pseudo-randomness good enough for most cases? Totally! But we want you to be aware of machine pseudo-randomness as it certainly is one aspect that separates simulation from real life. You might argue that, philosophically, what we call reality may be some uber-simulation already. But let's face it, if that were the case we'd all be doomed, so we might as well keep programming for now (wake us for the revolution).

Generating a random integer is easy, just use rand(). But you should have noticed that if you only use rand(), your computer will generate the same series of random numbers. For example:

for (int i = 0; i < 4; i++) {
    cout << rand();
}

This snippet of code results in a loop that repeats four times and therefore uses the rand() function four times. Each time we run this program, you'll notice something interesting: it always prints the same four "random" numbers. Why? By default, rand() relies on some default seed value to start from, generating pseudo-random numbers from that "point" forward. Each time we re-run the program, it uses that same default seed, and therefore generates the same series of random numbers. How do we get around this? By explicitly setting the seed itself. There are two common ways for doing this: asking the user to provide a seed, and using the current time as a seed.

Here's an example of asking the user:

int seed;
cout << "Enter seed: ";
cin >> seed;
srand(seed);
// now go do something fun with rand()

Of course, there's nothing preventing the user from entering the same seed every time. This can be handy in some cases when you're testing your program, but usually you'll want "real" pseudorandomness. In that case, use something that is always changing: time.

#include <ctime>
// ...
srand( time(NULL) );
// now go do something fun with rand()

Now we're seeding randomness using the current time, which is consistently different each time the program is run. Notice that the ctime library was included.

But... what about random numbers within a range?

You'll notice that rand() can generate some pretty large integer numbers. That's great if you want to torture your user in a number guessing game ("Guess a number between 0 and quadrillion"). But usually you'll want to ask the computer to provide a random number within a particular range. You do this by leveraging % (mod).

rand() % 10;

Think about this. If we gave you any number, asked you to divide that number by 10 and to tell us the remainder, that remainder will always be some number between 0 and 9, inclusively. Remember, the % operator is like asking "What is the remainder when the number on the left is divided by the number on the right?".

What if you wanted a number between -25 and 25?

rand() % 51 - 25;

Hoooly mooly! Think about how that works and bring it up at the next computer programming after-party.

Instructions

Every aspiring game programmer's first game should be the suspensful classic Guess the Number. Your goal for this assignment is to exercise your knowledge of selection statements (if/else-if/else), looping constructs (while and for) and the use of rand().

Your game must adhere to the following interaction example.

Hold onto your pants, we're about to play guess-the-numbah!
Pick a number between 0 and 100: 20
Too low! Not even close!
Pick a number between 0 and 100: 75
Too high!
Pick a number between 0 and 100: 63
Too low! Oooh you're close!
Pick a number between 0 and 100: 64
That's right! You won the game in 4 tries.

Your game must use a random number between 0 and 100, inclusively. However, do not use srand(). By not seeding randomness properly, your program will be easier to test and easier to grade.

Your game must print "Too low!" or "Too high!" relative to the target number and the players' guess.

Your game must print "Oooh you're close!" if the number guessed differs from the target by 2 or less; and it must print "Not even close!" if the number guessed differs from the target by a value of 20 or more.

For example, if the target is 50 and the player enters 10, your program should print "Too low!" and "Not even close!" Where as if the player enters 52 your program should print "Too high!" and "Oooh you're close!"

When the correct number is guessed, your program must "You won the game in N tries" where N is the number of guesses the player made.

Requirements and Rubric

A friendly message from The Terminator, our grading program

*bzzzt* Hel-lo. I will check for the specific output:

I will check for *bzzzt* those words without regard for capitalization ("Too Low" is ok).

Anything else your program "says" is up to you. Please don't hurt my feelings. *bzzzt*

This work is worth 70 points.

Requirement Points Notes
Correct submission of src directory as a .zip file. 3
Place your name in the comment header in main.cpp 2
Does not use srand() 5
Generates a random number between 0 and 100 10
Accepts user input for a number 10
Uses a loop properly 10
Correctly prints "too low" 5
Correctly prints "too high" 5
Correctly prints "not even close" 5
Correctly prints "close" 5
Correctly prints "you won" and "N tries" 5
Correctly counts number of tries 5

Concepts Exercised: compilation, libraries, making decisions, declaring facts, repetitive tasks, simulation, application, fun, I/O