Thread: Problem with extremely beginner exercise

1. Problem with extremely beginner exercise

Hi. I am going through beginner exercises on a C++ tutorial. I came across the number guesser, and I was able to make a once-through program very easily. However, when I try to make a "play again" option, I get multiple playtime errors. It plays the first time, but when I guess the number (and for some reason, every time I play the program, that number is 39... is that supposed to happen?), it displays a blank line. Then, whether I input "y" or "n", it briefly displays my "win" output and asks if I want to play again before it automatically exits. I have no idea where to look.

Here is how I set it up:

Code:
```#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
srand(time_t(0)); //seed random number generator

int theNumber = rand() % 100 + 1; //random number between 1 and 100
int tries = 0;
int guess;
char again;

cout << "Welcome to Guess My Number!\n\n";//Welcome line

do
{
cout << "You have eight tries to guess the number.\nEnter a guess: ";//Rules
do
{

cin >> guess;//Player input

if (guess > theNumber)
cout << "\nToo high! Guess again: ";

if (guess < theNumber)
cout << "\nToo low! Guess again: ";

++tries;

} while (guess != theNumber,tries <7);//While loop, for wrong guess, and guesses number less than 8

if (guess == theNumber)
{
cout << "\n\nYou got it!  You guessed the number in " << tries + 1 << " tries!";//Correct answer
cout << "\nDo you want to play again (y/n)?";//Play again option
cin >> again;
}

if (tries < 7)
{
cout << "\n\nSorry, you took too many tries.";// Wrong answer, too many guesses
cout << "\nDo you want to play again (y/n)?";//Play again option
cin >> again;
}

} while (again == 'y');
return 1;
}```
Any help for a total noob will be greatly appreciated.

2. If you seed the random generator to the same number everytime, you'll get the same pseudorandom set.
Code:
`srand(time(NULL)); //This is the right way to seed`
Also:
Code:
`} while (guess != theNumber,tries <7);//While loop, for wrong guess, and guesses number less than 8`
is wrong...does that even compile?

You shouldn't return 1 from main unless there was an error. There are several other errors with that code, but start with those.

3. Originally Posted by UMR_Student
If you seed the random generator to the same number everytime, you'll get the same pseudorandom set.
Code:
`srand(time(NULL)); //This is the right way to seed`
Thanks, that's good to know. (edit) Though now that I have tried that, I put exactly what you gave me in there and got this warning:
warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
When I put time_t back in, I still got only 39. Any suggestions?
Also:
Code:
`} while (guess != theNumber,tries <7);//While loop, for wrong guess, and guesses number less than 8`
is wrong...does that even compile?
Actually, it does. I get no errors whatsoever when I compile with Visual Studio.
You shouldn't return 1 from main unless there was an error. There are several other errors with that code, but start with those.
Sorry, that was a mistype. I fixed that later, but then had to go back to my previous code and forgot to change that again.

So how would I make a do...while or a while loop or whatever loop I need to be able to have to requisites?

4. Code:
```do
{
std::cin.ignore(1000, '\n');
} while(guess != theNumber && tries < 7);```

5. Code:
```srand(static_cast<unsigned int>(time(NULL)));

//You want logical AND
while (guess != theNumber && tries <7) //This is the correct way```
While I'm at it, try not to put arbitrary numbers like 7 in your code, make constants
Code:
```const int NUM_TRIES = 7;
//...
int main()
{
...
}```
One more thing
Code:
```//This
if (tries < 7)
//Should be this
if (tries > 7)```
Along with Desolation's suggestion, you should be close

6. NULL should never be used. It's an ugly macro where 0 is always a better alternative.

7. >NULL should never be used. It's an ugly macro where 0 is always a better alternative.

That's an interesting opinion...

8. >> warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
This warning is ok, and srand(time(0)) is what you should use rather than srand(time_t(0)). If you use time_t(0), you are just casting 0 to a time_t type and passing it to srand, which means you are always seeding srand with 0. If you use time(0), you are getting the current time, so each time you run your program you will be using a different seed. That's what you want.

The warning is because time(0) returns a time_t, which is different than unsigned int. You can ignore the warning, or cast the value like this (I think): srand(unsigned(time(0));

Note that there might be some debate whether that is guaranteed to always work, but in practice you should be fine. Feel free to do some searching on the topic if you are interested in the details (eternallyconfuzzled.com has information about the use of rand).

9. Yes! I got it!
I took your suggestions, and on top of that, I moved most of the variables and constants into the do loop, most important of which was "theNumber", which made it randomize the number to guess each time. That's kind of important I think. I also had to put some manual break in there for reading the number of tries to make it not display the guess again when you went over the limit. There were also a few other small changes that I don't remember the details of.
Here's my final code for those interested:
Code:
```// game1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
srand(static_cast<unsigned int>(time(NULL))); //seed random number generator

char again;

cout << "Welcome to Guess My Number!";

do
{
const int MAX_TRIES = 7;
int theNumber = rand() % 100 + 1; //random number between 1 and 100
int tries = 0, guess;
std::cin.ignore(1000, '\n');

cout << "\nYou have eight tries to guess the number.\nEnter a guess: ";

do
{
cin >> guess;
++tries;

if (tries > MAX_TRIES)
{
break;
}
if (guess > theNumber)
{
cout << "\nToo high! Guess again: ";
}
if (guess < theNumber)
{
cout << "\nToo low! Guess again: ";
}

} while (guess != theNumber && tries <= MAX_TRIES);

if (guess == theNumber)
{
cout << "\n\nYou got it!  You guessed the number in " << tries << " tries!";
}
if (tries > MAX_TRIES)
{
cout << "\n\nSorry, you took too many tries.";
}
cout << "\nDo you want to play again (y/n)?";
cin >> again;
} while (again == 'y');
return 0;
}```
Thanks all for your help. This has made me very happy. Any suggestions on what to work on next?

10. I'd move that constant outside of the do..while loops and all that casting in srand() is really ugly. srand(time(0)) is fine, even though there is a warning.

11. I was always taught to so it this way

Code:
`srand((unsigned)time(0));`
But the beauty of programming encourages a multiple way to achieve the same result.

12. Prelude warns that there is no guarantee that time_t is properly convertible to unsigned int. Her solution is to hash the bytes of the time_t returned by time(). A more C++ oriented example based on her code would be:
Code:
```unsigned int timeSeed()
{
using namespace std;

time_t now = time(0);
unsigned char* p = reinterpret_cast<unsigned char*>(&now);

unsigned int seed = 0;
unsigned int seed_multiplier = numeric_limits<unsigned char>::max() + 2U;
for (size_t i = 0; i < sizeof now; ++i)
{
seed = seed * seed_multiplier + p[i];
}

return seed;
}

// To seed the PRNG.
srand (timeSeed());```