How many rounds of Tenzi does it take to win?

[This article was first published on R on jmarriott.com, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

I spent some time over Christmas playing games of chance with my in-laws. Some of them didn’t have any strategy at all, and they left me wondering what the odds were of wining. In the case of Tenzi, the only thing you can really do to get better at the game is to roll and read dice faster. If you’re not familiar with the rules, you can find them here.

Let’s start by looking at how many rolls it takes to win. We’ll be using R, and this post assumes some familiarity with that language. First we’ll load the tidyverse.

library(tidyverse)

There is probably a straightforward way to mathematically solve this problem, but it will be quite easy to simulate, so that’s the approach I’m going take. I’ll start by simulating a roll of ten dice, chose the most comon number to keep rolling, and then roll the diminishing dice until they all have the same result.

# Roll ten dice, get the count of the number with the most rolls
dice_rolls <- data_frame(roll = sample(1:6, 10, replace = TRUE)) %>%
  group_by(roll) %>%
  summarize(count = n()) %>%
  arrange(desc(count))
## Warning: `data_frame()` is deprecated, use `tibble()`.
## This warning is displayed once per session.
# Record the chosen number
roll_int <- as.integer(dice_rolls[1, 1])

# Record the number of dice rolled with the chosen number
count_int <- as.integer(dice_rolls[1,2])

# Count the number of times a hand of dice is rolled
roll_count_int <- as.integer(1)

while(count_int < 10) {
  count_int = count_int + data_frame(roll = sample(1:6, 10 - count_int, replace = TRUE)) %>%
    filter(roll == roll_int) %>%
    length()
  roll_count_int = roll_count_int + 1
}

On this particular simulated series of rolls, it took 7 rolls to achieve ten dice with the number 1.

Let’s turn this code into a function that we can call over and over again to create some data we can look at to figure out how many rolls it usually takes to win.

round_of_tenzi <- function() {
  # Roll ten dice, get the count of the number with the most rolls
  dice_rolls <- data_frame(roll = sample(1:6, 10, replace = TRUE)) %>%
  group_by(roll) %>%
  summarize(count = n()) %>%
  arrange(desc(count))
  
  # Record the chosen number
  roll_int <- as.integer(dice_rolls[1, 1])
  
  # Record the number of dice rolled with the chosen number
  count_int <- as.integer(dice_rolls[1,2])
  
  # Count the number of times a hand of dice is rolled
  roll_count_int <- as.integer(1)
  while(count_int < 10) {
    count_int = count_int + data_frame(roll = sample(1:6, 10 - count_int, replace = TRUE)) %>%
      filter(roll == roll_int) %>%
      length()
    roll_count_int = roll_count_int + 1
    }
  return(roll_count_int)
  }

Now we’re ready to simulate rolling the dice a bunch of times. Just running the function a few times in the console, it looks like the average number of rolls that it takes to win will be somewhere from seven to nine.

# Create a dataframe to store all the results in
rolls_df <- data_frame(num_rolls = rep(0, 1e+06))

# Iterate through the dataframe, running a simulated instance of Tenzi for each row
for (i in 1:1e+06) {
  rolls_df[i,1] <- round_of_tenzi()
}

That took about four hours to compute on my laptop. That would probably be too long for a production environment, but for a one-time computation that’s OK. I started it before I went to bed and it was ready in the morning.

Now, let’s take a look at the data.

rolls_df %>%
  ggplot(aes(x = num_rolls)) +
  geom_histogram(binwidth = 1) +
  ggplot2::scale_x_continuous(limits = c(2,10)) +
  ylab("Occurances") +
  xlab("Number of Rolls") +
  theme_classic()
## Warning: Removed 2 rows containing missing values (geom_bar).

It’s interesting that the distribution drops off so sharply after seven rolls. Let’s see what the probablility is of winning for each number of rolls.

rolls_df %>%
  group_by(`Number of Rolls` = num_rolls) %>%
  summarise(`Percent Probability` = n()/1e+04) %>%
  knitr::kable()
Number of Rolls Percent Probability
2 0.0003
3 0.0104
4 0.1444
5 1.2942
6 7.7944
7 31.0952
8 52.9072
9 6.7539

So, the person who gets all their dice in five-six rolls is likely the winner. And, if you’ve rolled ten times then you probably missed a dice and re-rolled it by accident.

I’m sure that there’s a more efficient way to simulate this problem. Maybe in a future post I’ll look into running my function in parallel which would reduce the runtime considerably. Also, it would be interesting to see the distrubution of the number of dice rolled each round. In other words, how often does a player have to roll only one dice two-three times before ending the round?

Comment belown on what improvements you see to this short excercise!

To leave a comment for the author, please follow the link and comment on their blog: R on jmarriott.com.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)