Craps is a casino game in which players standing around a table take turns rolling two dice. Before each round, players are given the opportunity to place a wager on the roller's success or failure. Players typically bet that the round of dice rolling will be successful. If they are right, the casino will double the money wagered. If they are wrong, they lose their money. In the long run, as will all gambling, craps players always lose their money.
A round begins with an initial roll. If the sum of the two dice on this initial roll is 7 or 11, then the player 'wins'. If the sum is 2, 3, or 12 then the player 'loses'. If the sum is anything else (4, 5, 6, 8, 9, or 10) this sum is established as 'point'. The player continues, hoping for a roll whose sum is equal to the point roll. If they achieve such a roll before rolling a 7, then they win. If they roll a 7 before repeating the point roll, they lose, having 'crapped out'. After the roller craps out, the dice pass to the next person around the table.
Write a program, craps.py, that simulates a round of craps. Running your program might look like this:
$ python craps.py You rolled 11 You win! $ python craps.py You rolled 3 You lose :( $ python craps.py You rolled 6 Press enter to roll again You rolled 11 Press enter to roll again You rolled 4 Press enter to roll again You rolled 7 You lose :( $ python craps.py You rolled 4 Press enter to roll again You rolled 5 Press enter to roll again You rolled 4 You win!
Note that the "Press enter to roll again" bit can be achieved by calling
raw_input("Press enter to roll again")
without saving the result in a
variable. After importing the random library with the line from random
import *
you can use the randrange
function to simulate rolling the two dice.
If your code for part 1 was something like mine, then there was more than one
place in the program where you were simulating dice rolling with randrange
.
Rewrite your code to use a function, rollDice
, in these places. This is a good
time to use a function, because we'd otherwise have to repeat the same code in more than
one spot.
The rollDice
function should have no parameters. It should return the sum of
two random dice rolls. Make sure you call this function in main
. After this
step there should be no calls to randrange
within your main
.
def rollDice():
"""
Purpose: simulate the rolling of two dice
Parameters: none
Returns: The sum of the two dice
"""
# Your code here
Extend the rollDice
function so it prints a visual representation of the
two dice rolled as a side effect, before returning the sum of the two dice.
At this point your program might look like this:
$ python craps-a.py |5| |4| You rolled 9 Please roll again |4| |6| You rolled 10 Please roll again |4| |5| You rolled 9 You win! bash-3.2$ python craps-a.py |4| |2| You rolled 6 Please roll again |4| |6| You rolled 10 Please roll again |4| |3| You rolled 7 You lose :(
Now we'll extend your program so you can play multiple rounds of craps. The
first step is to rename your main
function as playRound
. Then create
a new main
in which you invoke playRound
:
def playRound():
"""
Your comment here
"""
# What used to be main() here
def main():
keepPlaying = 'y'
while keepPlaying == 'y':
playRound()
keepPlaying = raw_input("Do you want to play again? (y/n) ")
main()
Read the code in this new main
and try to understand what it's doing. Then run
the program to make sure you can really play multiple games without having to
re-enter the $ python craps.py
command. Notice that now we have defined an
auxiliary function, playRound
, which itself makes use of another auxiliary
function, rollDice
. How do you think this would look on the stack diagram?
If in the above version of main
the user enters anything other than
'y', we will take that as a no response. That's ok, but we can do better.
Create a function getYNAnswer
in which you continue asking the user whether
they want to play again until you get a valid response, i.e. 'y' or 'n'.
Because you don't know how many invalid responses you will get before the user
enters something valid, it makes sense to use a while
loop here.
def getYNAnswer():
"""
Purpose: Get the user's yes/no response to whether they
want to play again.
Parameters: None
Returns: 'y' or 'n'
"""
Running the code at this point might look like:
$ python craps-a.py |6| |5| You rolled 11 You win! Do you want to play again? (y/n) yes Please enter y or n: no Please enter y or n: y |1| |2| You rolled 3 You lose :( Do you want to play again? (y/n) asdflkj Please enter y or n: n
Now we have a nice working program that makes use of three auxiliary
functions other than main
. They are getYNAnswer
, playRound
, and
rollDice
. At this point there are a number of interesting ways for you to
extend the program.
One extension is to incorporate the wagering aspect of craps. Give the user some initial stake and before each round ask them how much they want to wager on the round. Update their stake based on whether they win or lose. As 'the house' it's up to you whether you want to let the user go into debt or not.
Another interesting extension is to turn your program into a simulation that
attempts to figure out the odds of winning a round of craps. Take out the
print statements and user interaction aspects of the program, except to ask
the user how many rounds of craps they want to simulate. Use a for
loop to
simulate that number of rounds, recording how many wins occur. After the
simulation finishes, print the win percentage.
If you attempt this extension you may want to change the playRound
function
so it returns some indication of whether the round was a win or a loss. For
instance, playRound
might return True
for a win and False
for a loss.
You will have converted playRound
from a function that was called for its
side effects (printing and getting user input) to one that is called for its
return value (True
to indicate a win, False
for a loss).
Based on the rules of probability, people have calculated that there's about a .493 chance of winning a round of craps. See how close your simulation gets to this figure. If you only simulate a few rounds, the variance will be high and your win rate may be far away from .493. If you simulate many rounds (say on the order of 10000 or 100000) then your figure should be very close to .493.
A 49.3% chance of doubling your money is about as close to fair as it gets for a casino game. Still 49.3% is less than 50% and over time the house will always come out on top. It doesn't pay to gamble!