How to Write a Number Guessing Game in C++

28 04 2012

Someone on Yahoo Answers had written a number guessing game in C++ for a class and was asking about adding a feature that alerts the player if he had already guessed the number he just entered. His code so far was awful but probably worked well enough for him. He had one goto statement and was counting the number of tries backwards for reasons I can’t imagine. I tried to explain what he should do to make the code easier to read and maintain and how he might add the feature. I wound up deciding to just re-write the whole thing. When I went to submit my answer, Yahoo Answers informed me that it was on break, as in broken. So I’m going to put here where it totally doesn’t belong.

It works using 3 nested do/while loops. The outer most loop contains the game and loops when our player wants to play again. The loop inside that is the game loop and it runs until a game ending condition is met (the player either guesses correctly or gives up). The loop inside that one gets the player’s guess and re-runs if the guess is outside the range of the game or has already been guessed.

The inner-most loop adds the functionality the student was asking for.

// includes go here
using namespace std;

// Let's define our constants
const int MIN_NUMBER = 1;
const int MAX_NUMBER = 100;
const int EXIT_VALUE = -1;

int main()
{
	// seed the random number generator
	srand((unsigned int)time(NULL));

	// initialize our program variables
	int games = 0;			// counts number of games played
	int wins = 0;			// counts number of games won
	int total_guesses = 0;	// adds total guesses together to calc the average at the end
	char again = 'n';		// will == 'y' or 'Y' if we want to play again

	// Let's save our title as a string so we can reuse it latter and ensure it doesn't change.
	char* title = "Unfrozen Caveman's Stupid Number Guessing Game";

	cout << "*** You are playing " << title << "! ***\n\n";

	do // This loop will exit when we don't want to play the game any more
	{
		// init our per game variables
	// set our target to a random number between MIN_NUMBER AND MAX_NUMBER
		int target = rand() % (MAX_NUMBER-MIN_NUMBER+1) + MIN_NUMBER;

The student’s code had a function to get a random number that wasn’t quite implemented properly. I found it unnecessary (to define an external function), but you can do that if you want. rand() % MAX_NUMBER will give us a random number in the range of 0 and MAX_NUMBER-1 (0 to 99). rand() % (MAX_NUMBER) + MIN_NUMBER will work as long as MIN_NUMBER == 1, but we don’t want our code to break if our constants are changed even if we don’t plan on doing so. If MAX_NUMBER==50 and MIN_NUMBER==25, our random number needs to be constrained by 26 (50-25+1) before 25 is added to ensure the number is within range. I hope that makes sense.

		int guess = 0;				// record our guess
		int guesses = 0;			// count our guesses
		bool game_over = false;		// this will == true when reach an end of game condition ( win or lose)

		// Let's declare and initialize an array to store all of our previous guesses with
		// enough elements to ensure we won't run out. If MAX_NUMBER = 40 and MIN_NUMBER = 20,
		// then we need 40-20+1 = 21 elements to cover the maximum number of guesses possible
		int old_guess[MAX_NUMBER - MIN_NUMBER + 1];
		for (int i=0; i			old_guess[i] = 0;

I hope this makes sense too. Worst case scenario is that our player guesses every single wrong answer before “winning”. In that case we need to have enough elements in our old_guess array to cover every single wrong guess (and his final correct one). We could eliminate the +1 here, but that would necessitate checking later on for this highly unlikely case.


		do // this loop will run until and end of game condition occurs
		{
			bool good_guess = false;

			// This loop ensures that our number is in range and hasn't been guessed already. This
			// loop could easily be another do-while loop, as it has to run at least once
			while(good_guess == false)
			{
				// Explain our range and ask for a guess within it.
				cout << "Enter a number between " << MIN_NUMBER << " and " << MAX_NUMBER << " (-1 to give up): "; 				cin >> guess;

				good_guess = true;

				// If the guess is our exit value, skip the other checks
				if(guess == EXIT_VALUE)
				{}
				else if(guess > MAX_NUMBER)
				{
					cout<<guess<<" is higher than the range of this game. Try again."<<endl;
					good_guess = false;
				}
				else if(guess < MIN_NUMBER)
				{
					cout<<guess<<" is lower than the range of this game. Try again."<<endl;
					good_guess = false;
				}
				else
				{
					for (int i=0; i					{
						if (guess == old_guess[i])
						{
							// if the player guesses a number he already tried, he should be verbally abused
							cout << "You already guessed that on guess #" << (i+1) << " you idiot!" << endl;
							good_guess = false;
						}
					} // end for
				} //end if
			} // end while

			// Now that we have a valid guess, let's save it in our old_guess array and increment our counter
			old_guess[guesses] = guess;
			guesses++;

			// now for our normal checking
			if(guess==EXIT_VALUE)	// Do we have a quitter on our hands?
			{
				// quitting calls for some verbal abuse
				cout << "*** YOU GOD-DAMNED QUITTER!! ***\n";
				cout << "The number was " << target << endl << endl; 				game_over = true; 			} 			else if (guess > target)	// Did he guess too high?
				cout << guess << " is too high. " << endl;
			else if (guess < target)	// Did he guess too low?
				cout << guess << " is too low. " << endl;

The student’s code did not give “too low” or “too high” hints until the player had guessed five times, drastically reducing the tiny amount of fun present in my (and everyone else’s) version of this game.

			else if (guess == target)	// This could just be an else statement, because all other possibilities have been covered.
			{
				if (guesses == 1)
					cout << "!!!!HOLY HELL!!!! You fucking RAINMANED that shit! Just " << guesses << " guess!\n\n";
				else
					cout << "*** YOU GOT IT!! ***\n It took you "<< guesses <				game_over = true;
				wins++;
				total_guesses += guesses;
			}

I didn’t want the game to say “It took you 1 guesses” if the player happens to nail it (Rainman it) on the first try, so I added a special vulgar message for such a case.


		} while (game_over == false);

		games++;

		cout << "Would you like to play again? "; 		cin >> again;
		cout << "\n\n";

	} while ((again == 'y') || (again == 'Y'));

The student’s code only permitted the player to play 256 times (a curiously square number). I can only guess that this was intended to be like the Nintendo Wii suggesting you go outside and play after playing with it for several hours. You know, cuz number guessing games are so addictive.


	// lets calculate the average number of guesses it took our player to win
	float average = float(total_guesses) / float(wins);
	cout << "Thanks for playing " << title << endl;
	cout << "You played "<< games <	cout << "with an average of " << average << " guesses per win\n\n";

	cout << "Hit enter to exit.\n\n";
	cin.ignore();
	cin.get();

	return 0;
}

Wasn’t that fun? So, yeah, I’ve been programming computers as a hobby since I was 12 or so. I’ve spent years away from it, but I’ve been getting back into it lately. Feel free to point out anything you don’t like about my code or to ask questions about it or about your own code. If you want to know how to show code on wordpress.com, check out this thing I just learned. You can no longer find this full code without interruption at PASTEBIN, which is where you should go if you need to share code with others on the interwebs for a fairly limited amount of time.

Advertisements