patterncppModerate
C++ Hangman Game
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
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
The only difference is that
Data Driven programming.
Rather than have a big set of
This can be replace by an array access.
At the top of you program just add the different pictures.
Loading a vector
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:
Random Shuffle
Good try again. But this version (as you seem to know by the use of
Also
Data Structures
You put a lot of work into breaking the word and definition up.
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).
'\n' to std::endlThe 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)
{
....etcThis 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)
{
....etcstd::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.