I'm developing a small craps game in C++, and my C++ skills are a bit rusty. I really need someone to review my code to ensure that I have correctly implemented the game according to the rules.
Game rules:
- The player or shooter rolls a pair of standard dice
- If the sum is 7 or 11 the game is won
- If the sum is 2, 3 or 12 the game is lost
- If the sum is any other value, this value is called the shooter’s point and he continues rolling until he rolls a 7 and loses or he rolls the point again in which case he wins
- If a game is won the shooter plays another game and continues playing until he loses a game, at which time the next player around the Craps table becomes the shooter
My code:
#include <iostream>
#include <ctime>
using namespace std;
bool checkWinning(int roll);
int main(int argc, const char * argv[])
{
//create player aka shooter
//create pair of dice
unsigned int dice1=0;
unsigned int dice2 = 0;
//create roll
unsigned int roll = 0;
//create game loop
while(checkWinning(roll) == true)
{
dice1 = rand() % 6 + 1;
dice2 = rand() % 6 + 1;
roll = dice1 + dice2;
cout<< dice1<<" +"<< dice2<<" = "<< roll << endl;
//cout<< checkWinning(2) <<endl;
}
return 0;
}
bool checkWinning(int roll)
{
bool winner = true;
if( roll == 2 || roll == 3 || roll == 12)
return winner= false;
else
if(roll == 7 || roll == 11 )
return winner;
else
return winner;
};
-
2\$\begingroup\$ The shooter loses his turn if a 7 is rolled after there is a point. \$\endgroup\$dbasnett– dbasnett2013年09月18日 14:13:15 +00:00Commented Sep 18, 2013 at 14:13
3 Answers 3
The parameters in
main()
are only necessary if you're executing from the command line.You're not calling
std::srand()
nor including<cstdlib>
. However, if you're using C++11, bothstd::srand
andstd::rand
are not recommended due to certain computational complications (the C++11 pseudo-random number generators can be found under<random>
). But, for a simple program, it may not matter.In general, here's how to call
std::srand()
:// casting may just be necessary if warnings are generated // that will alert you if there's a possible loss of data // prefer nullptr to NULL if using C++11 std::srand(static_cast<unsigned int>(std::time(NULL)));
Only include this once, preferably at the top of
main()
. This is preferred because- It'll help you keep track of it, especially if it'll need to be removed at some point.
- If called repeatedly, you'll receive the "same random number" each time.
It's best to keep variables as close in scope as possible. Here,
dice1
anddice2
can be initialized in thewhile
-loop:unsigned int dice1 = rand() % 6 + 1; unsigned int dice2 = rand() % 6 + 1;
roll
, however, will need to stay where it is so that the loop will work.The
bool
-checking can be shortened:// these are similar while (checkWinning(roll) == true) while (checkWinning(roll))
// these are also similar while (checkWinning(roll) == false) while (!checkWinning(roll))
checkWinning()
takesint roll
, butroll
is alreadyunsigned int
. They should match.checkWinning()
's closing curly brace shouldn't have a;
. It's not a type.bool winner
seems redundant; just returntrue
orfalse
. Also, the conditions seem a little unclear. If the sum constitutes a win or a re-roll, how do you specifically distinguish the two? They both returntrue
. I'd at least rename the function for clarification. There's also a Boolean enum, but that may be overkill here (or even unnecessary as there are only two ending outcomes).There should be a final outcome message, indicating a win or a loss. Also, you're not giving the player the option to play another game if victorious (and until loss).
-
2\$\begingroup\$ Good points, but two nit picks: The parameters to main have nothing to do with if you're compiling from the command line, but rather how you're running (creating) it. And for
if using C++11, use nullptr instead
... You should also mention that if you're using C++11, run the hell away from srand()/rand(). rand() has terrible range, is a pain in the ass to clamp to a range without bias, and a 32 bit seed limit is rather meh (half ofstd::time()
gets truncated for example). Doesn't matter for a basic card game program, but CR brings out my inner pedant :). \$\endgroup\$Corbin– Corbin2013年09月18日 05:42:21 +00:00Commented Sep 18, 2013 at 5:42 -
\$\begingroup\$ @Corbin: Good points. I'll put those in with my current edits. \$\endgroup\$Jamal– Jamal2013年09月18日 05:43:43 +00:00Commented Sep 18, 2013 at 5:43
-
\$\begingroup\$ @Corbin: Also, I had no idea about
std::srand()
in this case. I did happen to come acrossstd::uniform_int_distribution
not too long ago. Would this be a valid solution for here? \$\endgroup\$Jamal– Jamal2013年09月18日 06:33:45 +00:00Commented Sep 18, 2013 at 6:33 -
2\$\begingroup\$ Yeah. You would use a
std::uniform_int_distribution<int>(1, 6)
to achieve the same functionality as what he's done. A full (conviently dice oriented) example is here: en.cppreference.com/w/cpp/numeric/random/… \$\endgroup\$Corbin– Corbin2013年09月19日 00:47:54 +00:00Commented Sep 19, 2013 at 0:47 -
1\$\begingroup\$ @Corbin: Awesome! It appears to work with my old compiler, too. Looks like I can toss out
rand()
from my own stuff. \$\endgroup\$Jamal– Jamal2013年09月19日 01:15:21 +00:00Commented Sep 19, 2013 at 1:15
Using % with rand is wrong.
Assuming your RAND_MAX is the same as mine 2147483647
then the probabilities for each number are:
dice1 = rand() % 6 + 1;
1: 357913942/2147483647 Notice a slightly higher probability for a 1.
2: 357913941/2147483647
3: 357913941/2147483647
4: 357913941/2147483647
5: 357913941/2147483647
6: 357913941/2147483647
The solution use C++11 random functionality.
Correct for the skew in C++03's rand()
Unfortunately I can't find a correct answer on SO for using rand().
int dieRoll() // return a number between 1 and 6
{
static int maxRange = RAND_MAX / 6 * 6; // note static so calculated once.
int result;
do
{
result = rand();
}
while(result > maxRange); // Anything outside the range will skew the result
return result % 6 + 1; // So throw away the answer and try again.
}
Note:
int result = rand() * 1.0 / range; // does not help with distribution
In addition to what @Jamal said...
The singular for "dice" is "die", so name your variables accordingly. It's C++, so Die deserves to be a class, with a Die.roll()
method. The constructor could call std::srand()
.
You should use a do-while loop. Then you could avoid having to artificially initialize all of your values to illegal 0 values.
Your checkWinning()
function could just be a switch
statement. It doesn't need a winner
variable, and can just return the result immediately. I see where you implemented rules 1.1 and 1.2, but I don't see any of your other game rules expressed anywhere in your code.