3.4 Simulating the Game of Craps
This section presents an application of Monte Carlo methods to the estimation of the probability of winning the game of “craps” as played in Las Vegas. The following example will illustrate how to generate random variates and collect statistics in a useful manner.
Example 3.9 (Simulating Craps) The basic rules of the game are as follows: one player, the “shooter”, rolls a pair of dice. If the outcome of that roll is a 2, 3, or 12, the shooter immediately loses; if it is a 7 or an 11, the shooter wins. In all other cases, the number the shooter rolls on the first toss becomes the “point”, which the shooter must try to duplicate on subsequent rolls. If the shooter manages to roll the point before rolling a 7, the shooter wins; otherwise the shooter loses. It may take several rolls to determine whether the shooter wins or loses. After the first roll, only a 7 or the point have any significance until the win or loss is decided. Using the KSL random and statistic packages give answers and corresponding estimates to the following questions. Be sure to report your estimates in the form of confidence intervals.
- Before the first roll of the dice, what is the probability the shooter will ultimately win?
- What is the expected number of rolls required to decide the win or loss?
The solution to this problem involves the use of the Statistic
class to collect the probability that the shooter will win and for the expected number of rolls. The following code illustrates the approach. The DUniformRV
class is used to represent the two dice. Two statistics are created to estimate the probability of winning and to estimate the expected number of rolls required to decide a win or a loss. A for loop is use to simulate 5000 games. For each game, the logic of winning, losing or matching the first point is executed. When the game is ended the instances of Statistic
are used to report the statistical results.
fun main() {
val d1 = DUniformRV(1, 6)
val d2 = DUniformRV(1, 6)
val probOfWinning = Statistic("Prob of winning")
val numTosses = Statistic("Number of Toss Statistics")
val numGames = 5000
for (k in 1..numGames) {
var winner = false
val point = d1.value.toInt() + d2.value.toInt()
var numberoftoss = 1
if (point == 7 || point == 11) {
// automatic winner
winner = true
} else if (point == 2 || point == 3 || point == 12) {
// automatic loser
winner = false
} else { // now must roll to get point
var continueRolling = true
while (continueRolling) {
// increment number of tosses
numberoftoss++
// make next roll
val nextRoll = d1.value.toInt() + d2.value.toInt()
if (nextRoll == point) {
// hit the point, stop rolling
winner = true
continueRolling = false
} else if (nextRoll == 7) {
// crapped out, stop rolling
winner = false
continueRolling = false
}
}
}
probOfWinning.collect(winner)
numTosses.collect(numberoftoss.toDouble())
}
val reporter = StatisticReporter()
reporter.addStatistic(probOfWinning)
reporter.addStatistic(numTosses)
println(reporter.halfWidthSummaryReport())
}
As we can see from the results of the statistics reporter, the probability of winning is just a little less than 50 percent.
Half-Width Statistical Summary Report - Confidence Level (95.000)%
Name Count Average Half-Width
--------------------------------------------------------------------------------
Prob of winning 5000 0.4960 0.0139
Number of Toss Statistics 5000 3.4342 0.0856
--------------------------------------------------------------------------------
Now let’s look at a slightly more complex static simulation.