The loop here is interesting. I agree that counting iterations should be zero-based whenever it makes sense, but I think counting down is also important. I foresaw the greater need for “number of tries remaining” over “current try”, so I wrote my loop like this:
void PlayGame() {
constexpr int MAX_TRIES = 5;
for (int tries = MAX_TRIES; tries > 0; tries--) {
cout << "Try " << (MAX_TRIES - tries + 1) << ": ";
if (tries > 1) {
cout << "You have " << tries << " guesses remaining...\n";
} else {
cout << "This is your last guess! make it count!\n";
}
GetGuess();
}
}
Here’s what it looks like for me:
Welcome to Bulls and Cows!
Can you guess the 5 letter isogram I'm thinking of?
Try 1: You have 5 guesses remaining...
Guess the word: one
Wrong!
Try 2: You have 4 guesses remaining...
Guess the word: two
Wrong!
Try 3: You have 3 guesses remaining...
Guess the word: three
Wrong!
Try 4: You have 2 guesses remaining...
Guess the word: four
Wrong!
Try 5: This is your last guess! make it count!
Guess the word: five
Wrong!
Do you want to play again (Y/N)?: n
Game Over :(
Press any key to continue . . .
I’m a PHP developer, so the for and if syntax is very familiar to me. I like to count down in for loops for a number of reasons. One reason is that I only have to use the variable value in the initialiser (currently a constant, but it will be variable later). More relevant is that the last iteration of the loop is always 1 (tries > 0). Personally, I find it looks more logical to always have > 0 or >= 0 as the condition. It’s much easier to plan for zero than to plan for a number which could change once the program is running.
In this particular case I have easy access to the number of guesses remaining which I think is more relevant than which try we are on. As an added bonus in later sections of the course, I’m pretty sure that checking a variable against a constant (like 0) is a tiny bit faster than checking a variable against a “getter”.
For example, this:
for (int tries = Game.GetMaxTries(); tries > 0; tries--)
… runs Game.GetMaxTries() once, which is probably faster than…
for (int current = 1; current <= Game.GetMaxTries(); current++)
… which runs the function for each iteration of the loop on top of your initialiser.
If you break it down, it works like this:
for ( A ; B ; C )
- A is done before the loop starts (this is the initialiser)
- B is done before each iteration of the loop to check if we should read the next line
- C is done after each iteration of the loop to prepare for the next check
In my game so far A happens once, B happens 5 times and C happens 4 times.
This could unintentionally have a performance impact later on in the course when we have one or more loops running each frame at 60fps.