This project will be to create a version of the game Hangman. Make sure to fully
ID: 3691549 • Letter: T
Question
This project will be to create a version of the game Hangman. Make sure to fully document your code with comments as you write it, use proper indentation, and eliminate all build warnings.
*Use iostream
Rules of the Game
The rules of hangman (for this project) are simple. The player tries to guess a phrase by suggesting letters. The phrase to guess is represented by a row of underscores, indicating the number of letters per word. If the player guesses a letter that occurs in the word, the letter appears in the correct positions. If the suggested letter does not occur in the word, one element of a hanged man stick figure is drawn as a tally mark. The game is over when either the player correctly guesses all the letters in the phrase or when the hangman is complete (after 5 incomplete guesses).
Demo of Game
Program Specification
This project id dividing into smaller problems that can be completed on at a time. Complete and thoroughly test each part before going on to the next part.
Part 1: Loading and processing phrases
The first step in creating your hangmen game is to load the phrases from a file, initialize the attributes of each phrase, and sort them by difficulty. The part is accomplished through the specifications in the last assignment.
Part 2: Print out the phrase with an underscore for each unguessed letter.
Create a function named phraseWithBlanks that accepts a constant reference to the text from a phrase and a constant reference to a string of correctly-guessed lowercase letters. The function will return a string representing the phrase where every unguessed letter is represented by a underscore character and each character is separated by a space. Non-letter characters should be output as is. For example, if the phrase text is "It's time to eat!" and the correctly guessed string is "io", then the function should return "I _ ' _ _ i _ _ _ o _ _ _ !".
Hint 1: You may find that the tolower function that can be used if you include the cctype helpful. Also, it may be helpful to create an isLetter function that returns true if a single character is a letter.
Hint 2: Use string's find function to see if a character in the phrase-text string exists in the correctly-guessed letters string.
Part 3: Select random phrase based on difficulty level
Create a function named getDifficultyLevel that displays three difficulty levels: (1) Easy, (2) Medium, and (3) Hard. The function should ask the user to enter a number for the difficulty level they wish to play at. The function should then validate the user input, making sure that it is an integer between 1 and 3 inclusive. If it is not, the function should prompt the user for input again until the input number is valid. When a valid input is entered, the function should return the requested difficulty level.
In the main function (or in a new function that you define and then call from main) write some code produce a random number that will the index to the next Phrase to be guessed. If the difficulty level is 1, the random number should fall within the first third of the indices of initialized Phrase in your sorted Phrase array. Likewise, if the difficulty level is 2, the number should fall in the second third of valid indices, and so forth. (See the posted video on random numbers for information about how to do this step.)
Create a loop that checks if the Phrase at the random index is unused isUnused == true. Keep generating new random indices until the index points to an unused Phrase. Add some temporary code to main to make sure everything is working correctly.
Part 4: The game loop
This step is were everything comes together into a playable game. Create a function called runGame that accepts a reference to a Phrase. Create a do...while loop that continues while the number of incorrect guesses is less than 5 and the number of correct guesses is less than the Phrase's guessesRequired. In that loop first call the drawGallows function (see the bottom of this assignment for code), then print the phrase with blanks, then prompt the user to enter a guess. Consider the following conditions based on the guess:
If the guess is not a letter, output an error message. For example, "'!' is not a valid guess. Please enter a letter."
Otherwise, if the guess has already been guessed, output an error message in the following format: "You have already guessed an 'e'."
Otherwise, if the guess is in the phrase, output "Good guess" and store the guess in a sting of correct guesses.
Otherwise, output the message, "Sorry, bad guess." and add the guess in a string of incorrect guesses.
After the loop, draw the gallows one more time and the phrase (with blanks as needed). Depending on the number of incorrect guesses, output either "You Win!" or "You're Dead! The phrase was:" followed by the phrase.
Call this function from main and make sure everything is working correctly.
Hint: It may be helpful to store the current phrase's text as an all-lowercase string to be used in comparisons. You may want to create a function named toLowerCase that accepts a constant reference to a string and returns that string, but with all lowercase letters.
Part 5: Allow the user to play multiple times per run.
Add a do...while loop to your main function that includes the necessary code to:
Select a phrase at random based on the chosen difficulty level
Run the game with the current phrase.
Mark the current phrase as used and maintain a count of the number of phrases asked.
If there are more phrases to be guessed at that difficulty level, ask the user if he/she would like to play again with this prompt, "Would you like to play again? (y/n): "
The loop should continue while there are more phrases to be guessed and the user inputs a 'y' to play again.
Test your code to make sure it works like the demo video and then you have created your own terminal game!
Code
Use the following function to draw the gallows
Explanation / Answer
#include <iostream>
#include <string>
#include <fstream>
#include <ctype.h> //header file to use isalpha function
#include <iomanip>
#include <cstdlib> //header file for random number generator
#include <ctime> //gives access to time function
using namespace std;
// struct to be used throughout the program containing phrase, #of unique letters,
//and if the phrase has been used
struct Phrase
{
string text;
string::size_type guessesRequired;
bool isUnused;
};
//global variables
int const ARRAY_SIZE = 256;
//prototypes
void loadPhrasesFromFile(string fileName, Phrase phrases[], int& arrayLength); // loads phrases from a file and creates the array length
void sortPhrases(Phrase phrases[], int arrayLength); // prints the phrases sorted according to difficulty
void printPhrases(Phrase phrases[], int arrayLength); //print the phrases unsorted
int uniqueLetterCount(const string& text); //determines how many unique letters in the phrase
string phraseWithBlanks(const string& text, const string& correctLoLetters); //creates the phrase with blanks for the game set up
int getDifficultyLevel(int level); // request a desired difficulty level from user
int randomIndex(int min, int max); //generates a random number between given range
void drawGallows(int missCount); // draws the gallows
void runGame(string& Phrase, int guessesRequired, int& noOfPhrasesGuessed); //loops through as user plays game guessing letters until phrase guessed or they lose
string toLowerCase(const string& Phrase); // function to reference a string and return string in lower case to be called in runGame function
int main()
{
int arrayLength = ARRAY_SIZE; //create a variable = to global ARRAYSIZE to be able to use size of array as a variable throughout program
string fileName = "phrases.txt"; // file of phrases to be read in to program
Phrase phrases[ARRAY_SIZE]; //array of phrases of struct type Phrase
int level = 0; //int to store desired user level
int randPhraseIndex= 0; // int to store random generator index number
int guessesRequired; //int to store the number of guesses required for phrase selected
string gamePhrase = ""; //string to store the phrase selected
int noOfPhrasesGuessed = 0;
int level1Count = 0; // count for phrases used in level 1
int level2Count = 0; // count for phrases used in level 2
int level3Count = 0; // count for phrases used in level 3
char playAgain; // char to input y/n answer to user wanting to play again
unsigned int seed = static_cast<unsigned int>(time(NULL)); //setting seed of starting value for random generator
srand(seed); //starts random number according to time
// call to function to load the phrases and set array length according to the number of phrases loaded
loadPhrasesFromFile(fileName, phrases, arrayLength);
// setting variable to use in random Index = to 1/3, 2/3 and 3/3for getting random phrase at chosen level
int level1 = (arrayLength / 3);
int level2 = (arrayLength * 2 / 3);
int level3 = (arrayLength);
//call to function to sort phrases according to guess required
sortPhrases(phrases, arrayLength);
do
{
//call function to get the desired difficulty level from the user
level = getDifficultyLevel(level);
// switch conditions to end the game if there are no more phrases to guess at the users desired play level.
switch (level)
{
case 1:
if (level1Count > level1) // condition that accounts for all phrases at level 1
{
cout << "There are no more phrases at level 1." << endl << endl;
goto stop;
}
level1Count += 1;
break;
case 2:
if (level2Count >= (level2 - level1)) // condition that accounts for all phrases at level 2
{
cout << "There are no more phrases at level 2." << endl << endl;
goto stop;
}
level2Count += 1;
break;
case 3:
if (level3Count >= ((level3-1)-level2)) // condition that accounts for all phrases at level 3
{
cout << "There are no more phrases at level 3." << endl << endl;
goto stop;
}
level3Count += 1;
break;
}
cout << endl << endl;
//switch to obtain a phrase according to the user desired difficulty level
do
{
switch (level)
{
case 1:
randPhraseIndex = randomIndex(0, level1); //generate random number from 1st third of array
gamePhrase = phrases[randPhraseIndex].text; //set gamePhrase = to the phrase chosen from random generator index
break;
case 2:
randPhraseIndex = randomIndex(level1 + 1, level2); //generate random number from 2nd third of array
gamePhrase = phrases[randPhraseIndex].text; //set gamePhrase = to the phrase chosen from random generator index
break;
case 3:
randPhraseIndex = randomIndex(level2 + 1, level3 - 1); //generate random number from last third of array
gamePhrase = phrases[randPhraseIndex].text; //set gamePhrase = to the phrase chosen from random generator index
break;
}
} while (phrases[randPhraseIndex].isUnused == true);
guessesRequired = phrases[randPhraseIndex].guessesRequired; //set the guesses required to guess the phrase according to the phrase from the random generator index
// call function to begin the game
runGame(gamePhrase, guessesRequired, noOfPhrasesGuessed);
phrases[randPhraseIndex].isUnused = true;
//loop to ask user if they want to play again
do
{
cout << "Would you like to play again? (y/n): ";
cin >> playAgain;
} while ((playAgain != 'y') && (playAgain != 'Y') && (playAgain != 'n') && (playAgain != 'N'));
//conditional to continue or break out of the game
if ((playAgain == 'y') || (playAgain == 'Y'))
{
continue;
}
else
break;
} while(noOfPhrasesGuessed < arrayLength); //game loop condition to end
stop:
cout << endl << "Thank you for playing HangMan!" << endl << endl;
return 0;
}
// void function to load phrases in from a file and initialize them into an array.
//each element of the array is a struct set to the members above in the struct Phrase
void loadPhrasesFromFile(string fileName, Phrase phrases[], int& arrayLength)
{
ifstream inFile;
inFile.open(fileName);
string line;
int count = 0;
//loop to input the phile of phrases
while (!inFile.eof() && (count <= arrayLength))
{
getline(inFile, line);
phrases[count].text = line;
phrases[count].guessesRequired = uniqueLetterCount(line);
phrases[count].isUnused = false;
count++;
}
inFile.close();
arrayLength = count; //array length variable to use throughout the program
}
// function to return the number of unique letters in a particular phrase
int uniqueLetterCount(const string& text)
{
string::size_type index = 0;
string unique;
int position;
string textLower = text;
string::size_type guessesRequired;
for (index = 0; index < textLower.size(); index++)
{
textLower[index] = tolower(textLower[index]); //convert phrase to lower case
position = unique.find(textLower[index]);
if (position == string::npos)
{
if (isalpha(textLower[index])) //determine if the char is a letter
{
unique = unique.append(1, (textLower[index])); // a string of the unique letters in the phrase
}
}
}
guessesRequired = unique.size(); // the guesses required to guess the phrase
return guessesRequired;
}
//void function to sort the phrases according to how many unique guesses will be required per phrase
void sortPhrases(Phrase phrases[], int arrayLength)
{
int minGuessReq;
Phrase temp;
int location;
for (int index = 0; index < arrayLength; index++)
{
minGuessReq = index;
for (location = index + 1; location < arrayLength + 1; location++)
{
if (phrases[location].guessesRequired < phrases[minGuessReq].guessesRequired)
minGuessReq = location;
}
temp = phrases[minGuessReq];
phrases[minGuessReq] = phrases[index];
phrases[index] = temp;
}
}
//void function to print to the screen an array of phrases. one phrase per line
void printPhrases(Phrase phrases[], int arrayLength)
{
//printing header file
cout << left << setw(10) << "Guesses" << endl;
cout << setw(15) << left << "Required";
cout << setw(47) << "Phrase";
cout << left << "Is Used";
cout << endl;
for (int i = 1; i < 76; i++)
{
cout << "_";
}
cout << endl;
//printing phrases array
for (int row = 0; row < arrayLength; row++)
{
cout << setw(9) << left << phrases[row].guessesRequired << " "; //setting the columns for print display
cout << setw(50) << left << phrases[row].text;
if (phrases[row].isUnused == false)
{
cout << "Unused";
}
else
{
cout << "Used";
}
cout << endl;
}
}
// function to create the phrase with blanks in place of the alpha characters separated by a space between each character
string phraseWithBlanks(const string& text, const string& correctLoLetters)
{
string blanksPhrase;
string::size_type index = 0;
string textLower = text;
int i = 0;
for (index = 0; index < textLower.size(); index++)
{
if (isalpha(textLower[index])) //determining if charactere is a letter using isalpha function
{
textLower[index] = tolower(textLower[index]); //converting letters to lower case
if (correctLoLetters.find(textLower[index]) != string::npos)
{
blanksPhrase.append(1, text[index]);
}
else
{
blanksPhrase.append(1, '_');
}
}
else
{
blanksPhrase.append(1, text[index]);
}
blanksPhrase.append(1, ' '); //adding spaces between characters
}
return blanksPhrase;
}
//function to request the user for a difficulty level to play at.
int getDifficultyLevel(int level)
{
//requesting the input from the user
cout << "Enter a number between 1 and 3 for the difficulty level you would like to play: ";
cin >> level;
cout << endl;
while (!(level >= 1 && level <= 3))
{
cout << "You must enter the numeral 1, 2 or 3. Pleaase re-enter the difficulty level you would like: ";
cin >> level;
}
return level;
}
//function to get a random number between a minimum and maximum value
int randomIndex(int min, int max)
{
int range = max - min + 1;
return rand() % range + min;
}
//function to loop through the game as user guesses letters.
void runGame(string& Phrase, int guessesRequired, int& noOfPhrasesGuessed)
{
int missCount = 0;
int correctGuesses = 0;
string correctLoLetters = "";
char guess;
string alreadyGuessed = "";
string missedLetters = "";
string lowerPhrase = toLowerCase(Phrase);
do
{
drawGallows(missCount); //draw the gallows and update and user guesses letters
cout << "Previous incorrect guesses: " << missedLetters << endl << endl; //print a string of the missed guesses by the user
cout << phraseWithBlanks(Phrase, correctLoLetters) << endl << endl << endl;
cout << "Enter a guess: ";
cin >> guess;
cout << endl;
if (!isalpha(guess)) //if not a letter - ask user to input letter again
{
cout << guess << " is not a valid guess. Please enter a letter: ";
cin >> guess;
cout << endl;
}
else if (alreadyGuessed.find(guess) != string::npos) //if letter guessed is already guessed - ask user to guess another letter
{
cout << "Error: You have already guessed an " << guess;
cout << endl;
}
else if (lowerPhrase.find(guess) != string::npos) // if letter is a part of the phrase - fill in blank with correct letter
{
cout << "Good guess!" << endl;
correctLoLetters.append(1, guess);
correctGuesses += 1;
}
else
{
cout << "Sorry, bad guess." << endl; // if letter is not a part of the phrase increment missed count integer and add letter to missed letters string
missedLetters.append(1, guess);
missCount += 1;
}
alreadyGuessed.append(1, guess);
} while (missCount < 5 && correctGuesses < guessesRequired); //condition to end game
drawGallows(missCount);
if (missCount >= 5) //conditional to tell user if they won or lost and what the phrase was
{
cout << "Your Dead! The phrase was "" << Phrase << ""." << endl << endl;
}
else
{
cout << "You Win! The phrase was "" << Phrase << ""." << endl << endl;
}
noOfPhrasesGuessed += 1;
}
void drawGallows(int missCount)
{
// Output the top of the gallows
cout
<< " +----+ "
<< " | | ";
// Output the stand and body
switch (missCount)
{
case 0:
cout
<< " | "
<< " | "
<< " | "
<< " | ";
break;
case 1:
cout
<< " | O "
<< " | | "
<< " | "
<< " | ";
break;
case 2:
cout
<< " | O "
<< " | /| "
<< " | "
<< " | ";
break;
case 3:
// The \ will translate as '', because it is a special char
cout
<< " | O "
<< " | /|\ "
<< " | "
<< " | ";
break;
case 4:
cout
<< " | O "
<< " | /|\ "
<< " | \ "
<< " | ";
break;
default:
cout
<< " | O "
<< " | /|\ "
<< " | / \ "
<< " |You're Dead ";
}
// Output the base
cout << " ============= " << endl;
}
//function to convert phrase in runGame function to lower letters
string toLowerCase(const string& Phrase)
{
string::size_type index = 0;
string unique;
int position;
string textLower = Phrase;
for (index = 0; index < textLower.size(); index++)
{
textLower[index] = tolower(textLower[index]); //converting to lower letters
position = unique.find(textLower[index]);
if (position == string::npos)
{
if (isalpha(textLower[index]))
{
unique = unique.append(1, (textLower[index])); //creating a string of the letters
}
}
}
return textLower;
}
sample output
Enter a number between 1 and 3 for the difficulty level you would like to play: 1
+----+
| |
|
|
|
|
=============
Previous incorrect guesses:
Enter a guess: w
Sorry, bad guess.
+----+
| |
| O
| |
|
|
=============
You Win! The phrase was "".
Would you like to play again? (y/n): n
Thank you for playing HangMan!
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.