HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

C++ Hangman Game

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
gamehangmanstackoverflow

Problem

I've been working in C++ for awhile now, but always like for others to look over my code as much as I can get them to. My main concerns are if I've made something overly complicated or if I've broken any general conventions in my code. Anyways, thank you for reviewing and I hope you enjoy playing the game if you choose to.

Code:

```
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

void prompt(const int& rMaxWrongGuesses, int& rWrongGuesses, std::string& rGuessedLetters, std::string& rSoFar);
char getGuess(std::string& rGuessedLetters, const std::string& rTheWord, std::string& rSoFar, int& rWrongGuesses);
void checkGuess(char guess, const std::string& rTheWord, std::string& rSoFar, int& rWrongGuesses);
void shutDown(int& rWrongGuesses, const int& rMaxWrongGuesses, const std::string& rTheWord);
void drawGallows(int& rWrongGuesses);

int main()
{
//setup
const int kMaxWrongGuesses = 8; //maximum number of incorrect guesses allowed

// Gets list of words from file and assigns them to vector by line
std::vector words; // collection of possible words to guess
std::ifstream myfile("words.txt");
std::copy(std::istream_iterator(myfile),
std::istream_iterator(),
std::back_inserter(words));

// Shuffles Words
srand(static_cast(time(0)));
random_shuffle(words.begin(), words.end());

// Split Words and Definitions
std::stringstream ss(words[0]);
std::string item;
char delim = ',';
while (std::getline(ss, item, delim)) {
words.push_back(item);
}

// Find all characters after a comma in kTheWord and erase them.
std::string kTheWord = words[0];
kTheWord = kTheWord.substr(0, kTheWord.find(",", 0));

// Initialize Hint and strip underscores used in file
std::string hint = words.back();
std::replace(hint.begin(), hint.end(), '_', ' ');

// Set Variables used in game
int wrongGuesses = 0;
std::string soFar(kTheWor

Solution

Prefer '\n' to std::endl

The only difference is that std::endl will flush the stream after putting the '\n' character on it. Flushing the stream manually is almost always a waste of time as the stream will auto flush when required and any attempt by a human is ultimately at the wrong time.

Data Driven programming.

Rather than have a big set of if else blocks. Put the data you want to draw into an array and just print the appropraitare array element.

if(rWrongGuesses==8) 
 { 
  std::cout<< picture1; 
 } 
 else if(rWrongGuesses==7) 
 { 
  std::cout<<picture2; 
 } 
 else if(rWrongGuesses==6) 
 {
  ....etc


This can be replace by an array access.

std::cout << picture[rWrongGuesses];


At the top of you program just add the different pictures.

std::string const picture0 = "\n\n" 
                             "   +       \n"
                             "   |       \n" 
                             "   |       \n" 
                             "   |       \n" 
                             "   |       \n" 
                             "   |       \n" 
                             "  =============\n\n"; 
 .... etc
 std::vector  picture{ picture0, picture1, picture2 ....};


Loading a vector

std::vector words;
std::ifstream myfile("words.txt");
std::copy(std::istream_iterator(myfile),
    std::istream_iterator(),
    std::back_inserter(words));


Nice try. But you don't need to do all that work. The standard vector can be constructed using two iterators. So we can simplify the above too:

std::ifstream myfile("words.txt");
std::vector words(std::istream_iterator(myfile),
                               std::istream_iterator());


Random Shuffle

// Shuffles  Words
srand(static_cast(time(0)));
random_shuffle(words.begin(), words.end());


Good try again. But this version (as you seem to know by the use of srand()) uses the old random number generated. This is not a great random number generator. Its absolutely fine for programs like this. But it is worth learning to use the new random number generator.

Also random_shuffle will be removed in C++17 (it was deprecated in C++14). So prefer to use shuffle().

std::random_device rd;
std::mt19937 g(rd());
std::shuffle(words.begin(), words.end(), g);


Data Structures

You put a lot of work into breaking the word and definition up.

// Find all characters after a comma in kTheWord and erase them.
std::string kTheWord = words[0];
kTheWord = kTheWord.substr(0, kTheWord.find(",", 0));

// Initialize Hint and strip underscores used in file
std::string hint = words.back();
std::replace(hint.begin(), hint.end(), '_', ' ');


Note: Also reusing the word array to hold the definitions is bad style. Use a new varaible rather than re-use the same structure for multiple things.

This is all part of the main section of the code. I would separate this into its own class so that you read the words and definitions all in one go.

Assuming we still use the same definition file (but don't replace the space with underscores).

class Word
 {
     std::string          word;
     std::vector  definitions;

     friend std::istream& operator>>(std::istream& s, Word& data)
     {
         std::string line;
         if (std::getline(s, line))
         {
             std::stringstream linestream(line);
             if (linestream >> data.word)
             {
                 data.definitions = std::vector(std::istream_iterator(linestream),
                                                        std::istream_iterator());
             }
         }
         return s;
     };

    // Now in main we can simply load the words like this:
    std::ifstream myfile("words.txt");
    std::vector   words(std::istream_iterator(myfile),
                               std::istream_iterator());

Code Snippets

if(rWrongGuesses==8) 
 { 
  std::cout<< picture1; 
 } 
 else if(rWrongGuesses==7) 
 { 
  std::cout<<picture2; 
 } 
 else if(rWrongGuesses==6) 
 {
  ....etc
std::cout << picture[rWrongGuesses];
std::string const picture0 = "\n\n" 
                             "   +       \n"
                             "   |       \n" 
                             "   |       \n" 
                             "   |       \n" 
                             "   |       \n" 
                             "   |       \n" 
                             "  =============\n\n"; 
 .... etc
 std::vector<std::string>  picture{ picture0, picture1, picture2 ....};
std::vector<std::string> words;
std::ifstream myfile("words.txt");
std::copy(std::istream_iterator<std::string>(myfile),
    std::istream_iterator<std::string>(),
    std::back_inserter(words));
std::ifstream myfile("words.txt");
std::vector<std::string> words(std::istream_iterator<std::string>(myfile),
                               std::istream_iterator<std::string>());

Context

StackExchange Code Review Q#136721, answer score: 15

Revisions (0)

No revisions yet.