I’m in the process of learning C++ and this was an assignment for a class. It is a simple hangman game. The instructor gives no feedback, only a pass/fail remark. While this works, I would like to know where I can improve. Thank you very much in advance for your help.
/*************************************************************************
* Title: Hangman Game
*
* Write a program that plays the game of Hangman. The program should pick a
* word (which is either coded directly into the program or read from a text
* file) and display the following:
* Guess the word: XXXXXX
* Each X represents a letter. The user tries to guess the letters in the
* word. The appropriate response yes or no should be displayed after each
* guess. After each incorrect guess, display the diagram with another body
* part filled. After seven incorrect guesses, the user should be hanged. The
* display should look as follows:
* O
* /|\
* |
* / \
* After each guess, display all user guesses. If the user guesses the word
* correctly, display
* Congratulations!!! You guessed my word. Play again? yes/no
*************************************************************************/
#include <iostream> // std::cin/std::cout/endl
#include <string> // std::string
#include <vector> // vector
#include <ctime> // time for random seed
#include <random> // random
#include <cctype> // isalpha/tolower
#include <algorithm> // transform/count
// Get single character user input.
char getCharInput(const std::string prompt)
{
char input;
std::cout << prompt;
// Input from user.
std::cin.get(input);
if (std::cin.peek() != '\n')
// More than a single char input.
input = 0;
// Eat any remaining chars and LF.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return tolower(input);
}
// Check if character is already stored in list of guesses.
bool checkLetter(std::vector<char>& ltrs, const char c, const std::string response)
{
if (find(ltrs.begin(), ltrs.end(), c) == ltrs.end())
{
std::cout << response;
ltrs.push_back(c);
return true;
}
else
std::cout << "You already guessed \"" << c << "\"\n";
return false;
}
int main()
{
constexpr unsigned numWords{ 15 }, TOP{ 8 }, BASE{ 9 };
// Lambda random number generator [0...numWords].
auto rng = [=]() -> unsigned { return int(numWords * rand() / (RAND_MAX + 1.0)); };
// Seed the rng.
srand(static_cast<unsigned>(time(0))); rng();
do {
// Sample list of words to guess (five each 5, 6 & 7 character long).
std::string words[numWords] = {
"blimp", "inuit", "roach", "ankle", "could", "visual", "quartz", "studio",
"jockey", "hijack", "located", "alcohol", "crochet", "polymer", "humidor"
};
// Characters making up the gallows.
std::string gallows[] =
{
" | O\n | /|\\\n | |\n | / \\", // right leg (complete)
" | O\n | /|\\\n | |\n | /", // left leg
" | O\n | /|\\\n | |\n |", // torso
" | O\n | /|\\\n |\n |", // right arm
" | O\n | /|\n |\n |", // body
" | O\n | /\n |\n |", // left arm
" | O\n |\n |\n |", // head
" |\n |\n |\n |", // empty gallows
" ____\n | |\n", // gallows top
"\n _|_____\n" // gallows base
};
std::vector<char> guessedLetters; // List of guessed letters.
guessedLetters.clear(); // Empty the list.
unsigned remainingGuesses{ 7 }; // Number of guesses remianing.
unsigned rn{ rng() }; // Get a random number.
size_t remainingLetters{ words[rn].size() }; // Number un-guessed letters remaining in word.
std::string clue = { std::string(words[rn].size(), 'X') }; // Display word clue.
// Display program purpose.
std::cout << "Let's play a game of Hangman!\n\n";
// Loop until word is guessed or user is hung.
while (remainingLetters && remainingGuesses) {
// Display clue and get a user guess.
char g = getCharInput("Guess the word: " + clue + "\n");
if (isalpha(g)) {
// Replace 'X' with matching character.
transform(words[rn].cbegin(), words[rn].cend(), clue.begin(), clue.begin(),
[=](char s, char d) { if (s == g) { return g; } else return d; });
}
// Check if guessed character had any matches in word.
if (int matchedLetters = count(clue.cbegin(), clue.cend(), g))
// Correct guess, decrement remaining letters by proper amount.
remainingLetters -= (checkLetter(guessedLetters, g, "Good guess!\n") ? matchedLetters : 0);
else
// Wrong guess, decrement number of remaining guesses.
remainingGuesses -= (checkLetter(guessedLetters, g, "Wrong guess!\n") ? 1 : 0);
// Display results of guess.
std::cout << gallows[TOP] << gallows[remainingGuesses] << gallows[BASE];
std::cout << "Letters guessed: ";
for (char c : guessedLetters)
std::cout << c << " ";
std::cout << "\n\n";
}
// Display result of game.
if (!remainingLetters)
{
std::cout << "Congratulations!!! You guessed my word \"" << clue;
std::cout << "\" with " << guessedLetters.size() << " guesses!\n";
}
else
std::cout << "You've been hung!!!\n";
} while (tolower(getCharInput("Play again? yes/no ")) == 'y');
return 0;
}