to do that we will need to know the endpoints of our needle, which depends on the value of theta. If theta is less than or equal toπ/2, then the two points are (x−cos(θ)/4, y−sin(θ)/4) and (x+ cos(θ)/4, y+ sin(θ)/4). The first part of the if statement graph this line segment with segments() and a line width of 2. Now, if theta is not less than or equal toπ/2 then we set theta.new = pi - theta, call it ˆθ, as the first line after else. The endpoints of our needle are (x−cos(ˆθ)/4, y+ sin(ˆθ)/4) and (x+ cos(ˆθ)/4, y−sin(ˆθ)/4), which are again graphed with segments. Two right curly brackets end the code, the first ending the else statement and the second ending the for statement.
The Deadly Board Game 179
0 10 20 30 40 50
0.0120.0140.0160.0180.0200.0220.0240.026
1,000,000 Simulations
Square on Board
Probability
To simulate rolling the die and advancing along the board, we use sam- ple within cumsum. With sample(6,rolls,replace=TRUE) we get a vector of length rolls of random values from 1 through 6 with replacement, which is then converted to cumulative sums with cumsum. For example, cum- sum(1,4,2,5,3)=(1,5,7,12,15), which represents the squares we occupy during that sequence of rolls. This process is repeated withreplicatetrials times so that simulation is a rolls-by-trials matrix.
The functiontabulatewill tally all values in the matrix simulation less than or equal to max.square. Totals is a vector of length max.square where the first number represents the times square 1 was occupied, the second number is the times square 2 was occupied, and so on. In the next line, thesum(totals)is the total number of rolls so that totals/sum(totals)are probabilities. We can also obtain these values with prop.table(totals). We plot the probabilities with plot. The x-values are 1:max.square and the probabilities are the y-values.
We use type=“h” for a histogram-like plot. We label the axes with xlab and
ylab. The title of the plot is created with main. We usepasteto concatenate values and characters within quotes. Theformatfunction formats the number of trials so that it is not scientific notation and so that every three digits are separated by a comma with big.mark=“,”. It is clear that for the one coin game, we should place the coin on square 6. What are the exact percentages associated with each square?
To answer the question we want to order the vector probabilities, and we also need the associated squares with each probability. We assign square to be the numbers 1 through max.square. We convert probabilities to percent- ages. We define the data frame Percent.Position with the columns square and percent. We then sort the Percent.Position data frame by ordering the rows of the data frame by the percent column, Percent Position$percent. The “-”
sign in -Percent.Position$percent orders from largest to smallest; otherwise it would be smallest to largest. Leaving the column location after the comma blank returns all columns. In reading the last line, we have all the columns of Percent.Position with the rows ordered from largest to smallest based on the percent column.
R Code
> square=1:max.square
> percent=probabilities*100
> Percent.Position = data.frame(square, percent)
> Percent.Position[order(-Percent.Position$percent),]
square prob
6 6 2.565157
5 5 2.202578
11 11 2.094269 12 12 2.070616 10 10 2.056853 16 16 2.044828 ...
4 4 1.880249
7 7 1.806643
3 3 1.609853
2 2 1.386912
1 1 1.192080
We now move to solving the problem when we are allowed to place three coins on the board. We should note that landing on squares is not independent and so we shouldn’t necessarily use square 6, 5, and 11 from the one-coin analysis. From the one-coin analysis it is clear that the variability of landing on squares diminishes the farther along the board we go. Hence, we expect that
The Deadly Board Game 181 the optimal locations for placing the three coins occur in the early squares.
Consequently we set max.square to 20 after setting trials to 100000 and rolls to 8. In this case, the average roll of the die is 3.5 and so on average we should cover 28 squares. This is good enough and it will make it easier to follow the output with the examples below. As in the one-coin example, we usereplicate to generate our simulation of landing on squares withsamplereturning rolls random numbers from 1 to 6 with replacement to which we apply cumsum for the cumulative sum of the numbers. Executing simulation[,1:5] returns all rows by leaving no argument in the space before the comma for “all” and columns 1 through 5 of the matrix simulation.
R Code
> trials=100000
> rolls=8
> max.square=20
> simulation=replicate(trials,
cumsum(sample(6,rolls,replace=TRUE)))
> simulation[,1:5]
[,1] [,2] [,3] [,4] [,5]
[1,] 6 4 6 1 3
[2,] 12 9 7 5 8
[3,] 14 12 10 8 9
[4,] 19 17 14 14 14
[5,] 23 23 20 17 15
[6,] 27 25 21 23 17
[7,] 32 28 27 28 23
[8,] 33 34 33 33 27
We are going to construct a new two-column matrix from our simulation matrix. The first column will be the columns of simulation stacked on one an- other; the second column will denote the column number from the simulation matrix. We will call this new matrix landing.squares. The cbind command, column bind, combines vectors as columns in a matrix. Here c(simulation) returns the values of simulation as a vector by stacking the columns. Within therep, replicate, function we have two elements. The first isseq len(trials), a sequence from 1 to trials, and the second sets the number of times each element of seq len(trials) is repeated. For example,rep(seq len(5),each=2) returns 1 1 2 2 3 3 4 4 5 5. In summary,cbind is combining two vectors into a matrix where the first column is the columns of simulation stacked and the second column is the sequence from 1 to trials with each value repeated rolls times. We return the first 17 rows and all columns of landing.squares with landing.squares[1:17,], which can be compared to simulation[,1:5] above.
R Code
> landing.squares=cbind(c(simulation), rep(seq_len(trials),each=rolls))
> landing.squares[1:17,]
[,1] [,2]
[1,] 6 1
[2,] 12 1
[3,] 14 1
[4,] 19 1
[5,] 23 1
[6,] 27 1
[7,] 32 1
[8,] 33 1
[9,] 4 2
[10,] 9 2
[11,] 12 2
[12,] 17 2
[13,] 23 2
[14,] 25 2
[15,] 28 2
[16,] 34 2
[17,] 6 3
Our next step is to remove rows of landing.squares whenever the value exceeds max.square. We call this new matrix landing.squares.cut and we will use a logical statement within the square brackets of landing.squares. With landing.squares[, 1]<= max.square we apply a logical test to see if each value in the first column is less than or equal to max.square and returned is either TRUE or FALSE, creating a logical vector of TRUE and FALSE. With this vector as the first index of landing.squares, the TRUE rows will be kept. The empty second index means all columns are returned. We see the first 17 rows of landing.squares.cut and both columns with landing.squares.cut[1:17,]. We can compare this to landing.squares[1:17,] above.
R Code
> landing.squares.cut=
landing.squares[landing.squares[, 1] <= max.square,]
> landing.squares.cut[1:17,]
[,1] [,2]
[1,] 6 1
[2,] 12 1