Hello domweng,
I have been going over your code and even if you use
coder777's suggestion of the random_shuffle it might help, but in the end your use of "rand" may be the bigger problem. But if you do a shuffle before each new word is picked it may make a difference based on what you get from "rand".
To start with in "main"
srand(static_cast<unsigned int>(time(nullptr)));
is the more up-to-date way of using "srand". A good video that talks about the problems with "rand" is at
https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
This is what I ended up with for your variables:
1 2 3 4 5
|
//int word{}; // <--- ALWAYS initialize all your variables.
int wordCountIdx{};
string guess;
string entered;
string list[NUM_WORDS];
|
Eventually I found that line 1 is not needed.
You define a file stream and then open the file, but never check that it is open and usable. This may be more than it needs to be, but I found it useful in the beginning when working with files:
1 2 3 4 5 6 7 8 9 10 11 12
|
const std::string inFileName{ "wordlist.txt" }; // <--- Put File name here.
std::ifstream inFile(inFileName);
if (!inFile)
{
//std::cout << "\n File " << std::quoted(inFileName) << " did not open.\n"; // <--- Requires header file "<iomanip>".
std::cout << "\n File \"" << inFileName << "\" did not open.\n";
return 1;
//return (std::cout << "\n File \"" << inFileName << "\" did not open.\n"), 1;
}
|
The commented return can shorten this to just 1 line when you are ready.
The while loop and for loop for reading the file. I have to ask if you could find a more difficult way of doing this? As is it is not the best way to read a file. Either use a while loop or a for loop, but not both. Reading the file can be shortened to 1 line:
while (wordCountIdx < NUM_WORDS && inFile >> list[wordCountIdx]) wordCountIdx++;
. This way if there are more than 60 words in the file it will limit it to 60 and if there are less than 60 words the rhs will cause the condition to be false when it sets the "eof" bit on the stream. Either way "wordCountIdx" will have the correct number of words read from the file.
As you can see this can be condensed into 1 line:
1 2 3 4
|
//word = rand() % wordCountIdx;
//guess = list[word];
guess = list[rand() % wordCountIdx];
|
I used "wordCountIdx" here because it could be 60 or it could be less. It is based on how many words were read from the file.
After this the code needs reworking.
Starting with what was
word = rand() % wordCountIdx;
I put this line down to the closing } of the original
while (entered != "#")
in a do/while loop because there was no way to get back to picking a new word.
After the opening { of the do/while I put
int guesses{ 1 };
here. This way at the closing } of the do/while this variable is destroyed and if you loop back to the beginning it is remade and set to (0)zero for the next word.
For the original while loop I did this. It could be cleaned up a bit:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
while (entered != "#")
{
if (entered.length() != guess.length())
{
cout <<
"\n"
" The guess must be the same number of characters as your code word.\n"
" Your code is " << guess.length() << " characters long\n\n";
//" Please make your guess or enter # to stop: ";
//cin >> entered;
}
else if (entered == guess)
{
cout <<
"\n"
" You have guessed " << guesses << " times\n"
" You entered " << entered << "\n"
" You have guessed correctly! Good job.\n\n";
//" Please make your guess or enter # to stop: ";
break;
//cin >> entered;
}
else
{
std::cout <<
"\n Incorrect guess!\n\n";
//cin >> entered;
}
std::cout << " Please make your guess or enter # to stop: ";
std::getline(std::cin, entered);
guesses++;
}
|
In your original code the while loop on line 3 is not the best way. The if statement works better along with the else if and else.
The redundant code was commented out and moved to after the else.
When you get a match, or correct guess, you need to break out of the while loop to get to the do/while and start over picking a new word.
Should you enter a (#) it will leave both loops and the program will end normally.
I played with this function to use a more up-to-dare C++ way to generate a random number. It requires the header file "<random>" to use it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
int GetRandomNum(int wordCountIdx)
{
const int range_from{}; // <--- Initializes to (0)zero.
const int range_to{ wordCountIdx };
std::random_device rand_dev;
std::mt19937 generator(rand_dev());
std::uniform_int_distribution<int> distr(range_from, range_to);
//std::cout << distr(generator) << '\n';
return distr(generator);
}
|
Originally the function takes no parameters and "range_to is hard coaded in the function. I changed this part to use the value of "wordCountidx". You can use it if you want or "rand" does work.
Andy