cstdlib
has a function called
rand
which generates "random" numbers.
The rand
function returns an integer between 0 and
RAND_MAX (a number defined in cstdlib
that is
at least 32,767).
The number returned will at least appear to have been randomly
chosen in the range.
Player rolled 6 + 4 = 10 Player rolled 6 + 4 = 10 Player rolled 1 + 5 = 6 Player rolled 6 + 3 = 9 Player rolled 4 + 6 = 10You must ... define and use in your program a function with prototype
int roll1();
that simulates a single roll of the dice!cstdlib
library.
The prototype for rand
is:
int rand();How to do you transform a random number between 0 and RAND_MAX into a random number from 1 through 6? You might be tempted to do something like
1 + (rand()%6)
.
This would certainly give you
a number in the range 1,2,3,4,5,6 - and you can do it this way
if you want.
However, it turns out that
what rand()
really gives us is 31 random bits,
which means a random(ish) number between 0 and 2^31 - 1..
Since (2^31 - 1) % 6 = 1, I am slightly more likely to get
0 or 1 out of this than 2,3,4,5,6.
On the other hand, since 8 divides 2^31 evenly, if I
take rand() % 8
I am equally likely to get any of 0,1,2,3,4,5,6,7.
So, a better approach is to take rand() % 8
over and over until I get something in the range 0,1,2,3,4,5,
and then add one to the result. Do it the other way, and your
dice are ever-so-slightly loaded!
rand()
, it may be important to
repeat the same sequence.
Once the program is debugged, we can "seed" our RNG to create a
changing sequence.
We use the function srand
to "seed"
rand
. The idea is that the particular sequence
of seemingly random numbers rand
produces will
actually depend on the seed value - different seed values will
produce wildly different sequences.
Add to your code from Part 1 the following code:
int seed; cout << "Enter a seed value: "; cin >> seed; srand(seed);so that it appears as the first thing in "main". Execute your program three times using different seed values. Your results will be different for each new seed.
Execute your program three times using the same seed value. You will observe the same sequence! Here comes the Gaming Commission again! We do not want to have the user generate the "seed" because output can be predicted based on the seed value.
How can we seed our RNG without input from the user and have
unpredictable seed values?
Let's use a
function from the ctime
library.
The function call time(0)
returns an integer that is the number of seconds ellapsed since 00:00
hours, Jan 1, 1970.
This is
a continuously changing value that does not repeat, so it
makes a great seed value.
modify your Part 1 solution by including the
ctime
function and adding the line
srand(time(0));... as the first statement in your main() function. Run your program several times. You should no longer notice any predictable patterns in the results. Note: Only seed the random number generator once, typically at the beginning of a program. If you seed it before every call to
rand
, you'll be resetting the sequence
constantly, and it won't look very random.
// throw1() returns -1, 0 or a positive number. // -1 means house wins, 0 means player wins, a positive number // means neither won, and the number is the sum of the two dice rolls int throw1();Using the function throw1(), your program will simulate craps up until either the player or the house wins.
~/$ ./p3 Round 1: Player rolled 1 + 4 = 5 ... no winner, roll again! Round 2: Player rolled 1 + 2 = 3 House wins! ~/$ ./p3 Round 1: Player rolled 6 + 3 = 9 ... no winner, roll again! Round 2: Player rolled 2 + 4 = 6 ... no winner, roll again! Round 3: Player rolled 6 + 1 = 7 Player wins! ~/$ ./p3 Round 1: Player rolled 5 + 2 = 7 Player wins!
~/$ ./p4 Round 1: Player rolled 2 + 3 = 5 ... no winner, setpoint is 5! Round 2: Player rolled 1 + 3 = 4 ... no winner, roll again! Round 3: Player rolled 1 + 3 = 4 ... no winner, roll again! Round 4: Player rolled 4 + 1 = 5 Player wins! ~/$ ./p4 Round 1: Player rolled 1 + 2 = 3 House wins! ~/$ ./p4 Round 1: Player rolled 3 + 5 = 8 ... no winner, setpoint is 8! Round 2: Player rolled 6 + 6 = 12 House wins! ~/$ ./p4 Round 1: Player rolled 5 + 6 = 11 Player wins!Hint: think about adding a parameter setpoint to your throw1() function. This would allow you to deal with throws after the first. Of course you still have to deal with the first throw. You might make different functions to distinguish the first from the following throws. Or you might use arguments to throw1() to determine which case you're in. Or you might do something altogether different.
// reports to user, asks whether they want to continue, returns true // if they do, and false if they want to stop. bool playAgainQuery(int win, int loss);Below are some sample outputs.
$ ./p5 Round 1: Player rolled 4 + 2 = 6 ... no winner, setpoint is 6! Round 2: Player rolled 6 + 6 = 12 House wins! You've played 1 times, and are down $5. Would you like to play again? (y/n) y Round 1: Player rolled 5 + 6 = 11 Player wins! You've played 2 times, and are dead even. Would you like to play again? (y/n) y Round 1: Player rolled 4 + 3 = 7 Player wins! You've played 3 times, and are up $5. Would you like to play again? (y/n) y Round 1: Player rolled 5 + 1 = 6 ... no winner, setpoint is 6! Round 2: Player rolled 3 + 2 = 5 ... no winner, roll again! Round 3: Player rolled 2 + 4 = 6 Player wins! You've played 4 times, and are up $10. Would you like to play again? (y/n) n