stats_noob
stats_noob

Reputation: 5907

Simulating Dice Rolls in R

I am trying to code the following game in R:

I tried to manually simulate this as follows - I first used the "runif" command in R to "roll a dice" a large number of times, hoping that you will eventually see a 4 followed by a 6 (I don't know how to code this using "do until loops"). I repeated this 100 times and put all these rolls into a data frame:

roll_1 = floor(runif(100, min=1, max=6))

roll_2 = floor(runif(100, min=1, max=6))

roll_3 = floor(runif(100, min=1, max=6))

roll_4 = floor(runif(100, min=1, max=6))

roll_5 = floor(runif(100, min=1, max=6))

#etc 

roll_100 = floor(runif(100, min=1, max=6))

all_rolls = data.frame(roll_1, roll_2, roll_3, roll_4, roll_5, roll_100)

This looks as follows:

head(all_rolls)
  roll_1 roll_2 roll_3 roll_4 roll_5 roll_100
1      4      2      5      3      1        4
2      3      2      4      4      1        2
3      1      3      1      4      2        1
4      3      2      1      4      4        3
5      4      1      2      2      5        5
6      2      3      3      5      3        1

I then exported this data frame into Microsoft Excel and manually inspected each column and counted the row number at which a 6 appears when preceded by a 4. I then averaged this number for all columns and calculated the average number of times you need to roll a dice before you observe a 4 followed by a 6. This took some time to do, but it worked.

I am looking for a quicker way to do this. Does anyone know if "do until" loops can be used in R to accelerate this "game"?

Thanks

Upvotes: 5

Views: 14505

Answers (3)

PavoDive
PavoDive

Reputation: 6496

I considered a different approach to solve this problem, deviating from the exact instructions you received.

Create a sequence of rolls that is extremely large, so you can find 100 cases in which a 6 follows a 4:

x = sample(1:6, 1e6, TRUE)

The mean of rolls needed to get a 6 after a 4 is:

mean(diff(which(x == 4 & data.table::shift(x) == 6)[1:100]))

What you're doing there:

  • x == 4 & data.table::shift(x) == 6 is a vector of records for which a 4 is followed by a 6. This vector is a bunch of FALSEs and TRUEs.
  • which(x == 4 & data.table::shift(x) == 6)[1:100] is the indexes of those TRUEs (the first 100 TRUEs)
  • diff tells us how many rolls there were between consecutive matches.
  • mean gives us the average of the last value.

Upvotes: 2

Kra.P
Kra.P

Reputation: 15123

Sampling from dice is following categorical distribution. By using rcat function from extraDistr package, you can sample from categorical distribution

roll_game <- function() {
  count <- 2
  dices <- rcat(2, c(1/6 ,1/6, 1/6, 1/6, 1/6, 1/6))
  while(!(rev(dices)[2] ==4 && rev(dices)[1] ==6 )){
    dices <- c(dices, rcat(1, c(1/6 ,1/6, 1/6, 1/6, 1/6, 1/6)))
    count <- count+1
  }
  count
}

mean(replicate(100, roll_game()))

will get your answer

Upvotes: 0

Ronak Shah
Ronak Shah

Reputation: 389047

Instead of runif, I would sample 1:6 value since a die would have only values from 1 to 6 and will not have values like 1.23 etc.

This is how you can use while loop -

roll_from_4_to6 <- function() {
  n <- 1:6
  i <- 1
  previous_4 <- FALSE
  while(TRUE) {
    current_value = sample(n, 1)
    i <- i + 1
    if(previous_4 && current_value == 6) break
    previous_4 <- current_value == 4
  }
  i
}

Run it once.

roll_from_4_to6()

Run it 100 times and take the average.

mean(replicate(100, roll_from_4_to6()))

Upvotes: 3

Related Questions