Zombie Dice Simulation

A while back at an MadR Meetup hack night I spent some time working on a way to simulate the game Zombie Dice. Zombie Dice is made up of 13 six-sided dice, six green, five yellow, and three red. Each side of the die has either a foot symbol, a shotgun symbol, or a brain symbol. The player is a zombie, looking for victim’s brains and avoiding shotguns. The foot symbol means that the victim got away.

On the first turn, the player randomly selects three dice. Green dice are the best for the player, with four brains and one shotgun. Yellow has three brains and two shotguns. Red dice have two brains and three shotguns. The three selected dice are rolled. Shotguns and brains are set aside. Feet are kept to be rolled again on the next turn. If a player is shot three times their turn ends and they don’t get to add the brains to their score. After any turn they can choose to stop and let the next player go while adding any brains they have rolled to their score. Confusing? It’s actually an easy game to learn and play. You can see the game in action starting at about 10 minutes into this video:

After playing this game a few times I wondered if I could simulate this game in R to determine the best strategy. I decided to try it without spending much time on the project. I limited myself to what could be done in a single MadR meetup hack night.

The result was code that is a good start at simulating Zombie Dice but doesn’t follow the rules correctly. It works but doesn’t set aside the dice that rolled shotguns or brains. It also doesn’t allow for the user to set the strategy and just continues rolling until it wins the game or is shot three times (a better strategy seems to be for the player to stop when a few brains have been rolled). Here is what the (inaccurate) output looks like:

Maybe someone else wants to finish this project? The code is below and you can also view it on github at https://github.com/justinmeyer/zombie_dice_simulation.

# Set the number of games to play
games <- 10000

# Create a data frame to store the game results in
game_results <- as.data.frame(matrix(NA, games, 2))

library(data.table)
setnames(game_results, c("V1", "V2"), c("outcome", "round"))

game_results\$outcome <- as.factor(game_results\$outcome)
levels(game_results\$outcome) <- c("lost", "won")

# Create a loop that simulates the specified number of games

for (i in 1:games) {

print(paste0("############ GAME: ", i, " STARTED ############"))

# Create a loop that runs as long as the game hasn't been won or lost
round <- 0
count_brains <- 0
count_shotguns <- 0

while (count_brains < 13 & count_shotguns < 3) {

# Create matrix representing the 13 dice
# Brain = 1, runner = 0, shotgun = -1
dice <- matrix(NA, 13, 6)

dice[1, ] <- c(1, 1, 1, 0, 0, -1) # green
dice[2, ] <- c(1, 1, 1, 0, 0, -1) # green
dice[3, ] <- c(1, 1, 1, 0, 0, -1) # green
dice[4, ] <- c(1, 1, 1, 0, 0, -1) # green
dice[5, ] <- c(1, 1, 1, 0, 0, -1) # green
dice[6, ] <- c(1, 1, 1, 0, 0, -1) # green
dice[7, ] <- c(1, 1, 0, 0, -1, -1) # yellow
dice[8, ] <- c(1, 1, 0, 0, -1, -1) # yellow
dice[9, ] <- c(1, 1, 0, 0, -1, -1) # yellow
dice[10, ] <- c(1, 1, 0, 0, -1, -1) # yellow
dice[11, ] <- c(1, 0, 0, -1, -1, -1) # red
dice[12, ] <- c(1, 0, 0, -1, -1, -1) # red
dice[13, ] <- c(1, 0, 0, -1, -1, -1) # red

# Simulate a round by randomly drawing three dice from the 13
selected_dice <- dice[sample(1:nrow(dice), 3, replace = FALSE),]

# Simulate rolling the three selected dice
roll_result_1 <- sample(selected_dice[1, ], 1)
roll_result_2 <- sample(selected_dice[2, ], 1)
roll_result_3 <- sample(selected_dice[3, ], 1)
rm(selected_dice)

# Combine the results
round_results <- as.data.frame(rbind(roll_result_1, roll_result_2, roll_result_3))
rm(roll_result_1, roll_result_2, roll_result_3)

# Determine if the player won or lost
round_results\$count <- 1
round_brains <- sum(round_results\$count[round_results\$V1 == 1])
count_brains <- count_brains + round_brains

round_shotguns <- sum(round_results\$count[round_results\$V1 == -1])
count_shotguns <- count_shotguns + round_shotguns

rm(round_brains, round_shotguns)

# Add one to round and print number of rounds
round <- round + 1
print(paste0("###### Round: ", round, " ######"))

# Report brains count and shotguns count
print(paste0("Brains: ", count_brains))
print(paste0("Shotguns: ", count_shotguns))

# Report status of game at end of each round
if(count_brains >= 13 & count_shotguns < 3){print(paste0("Won in ", round, " rounds."))
game_results[i, 1] <- "won"
game_results[i, 2] <- round}

else if(count_shotguns >= 3){print(paste0("Lost in ", round, " rounds."))
game_results[i, 1] <- "lost"
game_results[i, 2] <- round}
else {print(paste0("Play another round."))}

rm(round_results)

}

print(paste0("############ GAME: ", i, " COMPLETE. ############"))

}

summary(game_results)
table(game_results\$round)

Phone Pad Interview Test Solutions in R

If you are interviewing for a programming job you may be asked to demonstrate your skills by solving a programming problem. One classic interview question is the phone pad interview question.

Old phone button pads used for dialing had one number and three or four letters on each key. Each number corresponded to letters so that a user could enter letters using the phone. For example, the button for 2 corresponds to A, B, and C. What is the Phone Pad Interview Question?

In the phone pad interview test the programmer is asked to write a program that returns all of the possible combinations of letters when the user selects three numbers. For example, if the user presses 2, 3, 4, the program should return:

BDG, BDH, BDI, BEG, BEH, BEI, BFG, BFH, BFI,

CDG, CDH, CDI, CEG, CEH, CEI, CFG, CFH, CFI

Note that two of the keys, 6 and 9, each have four letters associated with them while the other keys each only have three letters.

One Solution Using Loops

One solution I came up with uses loops (scroll down for the complete solution). First create the phone pad in R. Note that I don’t include 0 and 1 because they don’t have any letters associated with them.

# Create phone pad
two <- c("A", "B", "C")
three <- c("D", "E", "F")
four <- c("G", "H", "I")
five <- c("J", "K", "L")
six <- c("M", "N", "O", "P")
seven <- c("Q", "R", "S")
eight <- c("T", "U", "V")
nine <- c("W", "X", "Y", "Z")

Next I create some variables to represent the selected numbers.

# Choose three numbers
number_1 <- two
number_2 <- three
number_3 <- six

Then I create a variable to save the combinations to. NULL means that the variable is empty.

combinations <- NULL

Next create a series of loops. Each loop moves through each of the letters in one of the selected numbers. For example, if the number_1 is 2, the first loop will run three times, once for A, once for B, and once for C. When you put loops within each other like this they are referred to as nested loops.

Within the third loop the paste0 command concatenates the letters from each of the three loops together and enters them in the “combinations” object. For example, if the numbers selected were 2, 3, and 6, the first time R moves through the loops the result will be ADM because the first letter of the first loop is A, the first letter of the second loop is D, and the first letter of the third loop is M.

# Loop through the letters in number_1
for(i in number_1){

# Loop through the letters in number_2
for(j in number_2){

# Loop through the letters in number_3
for(k in number_3){

# Add each of the letters to the combinations object
combinations <- c(combinations, paste0(i, j, k))

}

}

}

Finally, print “combinations” so that the user can see the results of the phone pad interview test.

# Print all of the possible combinations
combinations
"AFP" "BDM" "BDN" "BDO" "BDP" "BEM" "BEN" "BEO" "BEP" "BFM" "BFN"
"BFO" "BFP" "CDM" "CDN" "CDO" "CDP" "CEM" "CEN" "CEO" "CEP" "CFM"
"CFN" "CFO" "CFP"

Here’s the whole first solution.

# Create phone pad
two <- c("A", "B", "C")
three <- c("D", "E", "F")
four <- c("G", "H", "I")
five <- c("J", "K", "L")
six <- c("M", "N", "O", "P")
seven <- c("Q", "R", "S")
eight <- c("T", "U", "V")
nine <- c("W", "X", "Y", "Z")

# Choose three numbers
number_1 <- two
number_2 <- three
number_3 <- six

# create an object to save the combinations to
combinations <- NULL

# Loop through the letters in number_1
for(i in number_1){

# Loop through the letters in number_2
for(j in number_2){

# Loop through the letters in number_3
for(k in number_3){

# Add each of the letters to the combinations object
combinations <- c(combinations, paste0(i, j, k))

}

}

}

# Print all of the possible combinations
combinations

Another Phone Pad Interview Test Answer Using a While Loop and For Loops

The second solution is a Rube Goldberg machine solution that I put together for fun. I wouldn’t recommend using this in a job interview! It works but is complicated and inefficient, using two types of loops and sampling (scroll down for the complete solution).

First create the phone pad in R. Note that I don’t include 0 and 1 because they don’t have any letters associated with them.

# Create phone pad
two <- c("A", "B", "C")
three <- c("D", "E", "F")
four <- c("G", "H", "I")
five <- c("J", "K", "L")
six <- c("M", "N", "O", "P")
seven <- c("Q", "R", "S")
eight <- c("T", "U", "V")
nine <- c("W", "X", "Y", "Z")

Next I create some variables to represent the selected numbers.

# Choose three numbers
number_1 <- two
number_2 <- three
number_3 <- six

Then create some additional variables to help control and monitor the loops.

# Create status and count objects
status <- "not enough"
count <- 0

Now create a while loop. A while loop continues to run until a condition is met that tells it to stop. In this case, the while loop runs as long as the variable status is set to “not enough”.

# Create a while loop that runs as long as all of
# the possible combinations have not been found
while(status == "not enough"){

Next create a variable called “combinations”. This happens within the while loop so it will happen every time the while loop runs.

# Create combinations object
combinations <- NULL

Next create a for loop. This runs within the while loop.

A for loop runs a specified number of times. In this case the for loop will run 100 times. Each time the for loop runs R will sample one letter from each of the selected numbers. The sampled letters will be concatenated by the paste0 command and added to the combinations variable.

For example, if the first selected number is 2 then the possible letters that could be sampled from number_1 are A, B, and C. If the second number is three then the possible letters that could be sampled from number_2 are D, E, and F. If the third number is six then the possible letters that could be sampled from number_3 are M, N, O, and P. If A, E, and N are sampled then “AEN” is added to combinations. Each time the while loop runs, the for loop runs 100 times, returning 100 randomly selected three letter combinations.

# Sample one letter from each of the chosen numbers
# Add that combination of letters to combinations
# Do this 100 times (needs to run at least as many times as there
# are possible combinations)
for(i in 1:100){
combinations[i] = paste0(sample(number_1, 1), sample(number_2, 1), sample(number_3, 1))
}

rm(i)

Now check to see if each of the possible combinations have been found. The number of combinations that should be found depends on the number of letters associated with each button pressed. For example, if all three buttons have three letters associated with them then there should be 3 * 3 * 3 = 27 combinations.

If all of the possible combinations have been found the set status to “all possible”.

Note the use of the “unique()” command. This returns only unique values. For example, if you have a vector containing ABZ, ABZ, ABC and you apply unique, it will return ABZ, ABC because the second ABZ is a duplicate.

# Check to see if all the possible combinations have been found
# If all of the possible combinations are found, change status from
# "not enough" to "enough" so that the while loop will stop
if((length(number_1) + length(number_2) + length(number_3) == 9 & length(unique(combinations)) == 27) |
(length(number_1) + length(number_2) + length(number_3) == 10 & length(unique(combinations)) == 36) |
(length(number_1) + length(number_2) + length(number_3) == 11 & length(unique(combinations)) == 48) |
(length(number_1) + length(number_2) + length(number_3) == 12 & length(unique(combinations)) == 64)){
status <- "all possible"
}

Next add one to the count each time the while loop runs.

# Add one to count every time the while loop runs
count <- count + 1

Then print the number of unique letter combinations that were found, print the number of times the while loop has run, and close the while loop.

# Print the results of each while loop
print(paste0("length: ", length(unique(combinations))))
print(paste0("count: ", count))
}

Finally, print the combinations that were found.

# When the while loop stops, print all of the possible combinations
unique(combinations)

This solution is fun because it doesn’t solve the problem directly. Instead, R samples the possible letters to make 100 random three letter combinations. If there are enough unique (non-duplicated) three letter combinations that all of the possible combinations must be there, R stops the while loop and prints the combinations.

When this program runs it looks something like the below. In this case, the while loop had to run four times before it returned the right number of unique combinations. Each of the first three times it ran there were 34 unique combinations returned. The fourth time it ran all of the 36 possible combinations were returned. This is interesting because 100 combinations were returned each time. This means that all of the other combinations were duplicates.

If you change the 100 to a higher number R will be more likely to find all of the combinations on each attempt. If you change the 100 to a number that is smaller than the number of possible combinations the while loop will run forever because it won’t be able to find all of the possible combinations.

"length: 34"
"count: 1"
"length: 34"
"count: 2"
"length: 34"
"count: 3"
"length: 36"
"count: 4"

"CFN" "CEM" "ADP" "AFN" "BDO" "ADM" "AEN" "BDN" "BFO" "ADN" "BEN" "BEO"
"AEO" "CEP" "CDM" "CFM" "CDO" "BEM" "AFO" "CDN" "AEP" "CEO" "CFO" "BDP"
"AFP" "ADO" "BFP" "CFP" "BDM" "CDP" "AFM" "AEM" "BEP" "BFM" "BFN" "CEN"

Here’s the whole second solution.

# Create phone pad
# O and 1 are not needed because they don't represent any letters
# Note that six and nine have four letters while the others have three
two <- c("A", "B", "C")
three <- c("D", "E", "F")
four <- c("G", "H", "I")
five <- c("J", "K", "L")
six <- c("M", "N", "O", "P")
seven <- c("Q", "R", "S")
eight <- c("T", "U", "V")
nine <- c("W", "X", "Y", "Z")

# Choose three numbers
number_1 <- two
number_2 <- three
number_3 <- six

# Create status and count objects
status <- "not enough"
count <- 0

# Create a while loop that runs as long as all of
# the possible combinations have not been found
while(status == "not enough"){

# Create combinations object
combinations <- NULL

# Sample one letter from each of the chosen numbers
# Add that combination of letters to combinations
# Do this 100 times (needs to run at least as many times as there
# are possible combinations)
for(i in 1:100){
combinations[i] = paste0(sample(number_1, 1), sample(number_2, 1), sample(number_3, 1))
}

rm(i)

# Check to see if all the possible combinations have been found
# If all of the possible combinations are found, change status from
# "not enough" to "enough" so that the while loop will stop
if((length(number_1) + length(number_2) + length(number_3) == 9 & length(unique(combinations)) == 27) |
(length(number_1) + length(number_2) + length(number_3) == 10 & length(unique(combinations)) == 36) |
(length(number_1) + length(number_2) + length(number_3) == 11 & length(unique(combinations)) == 48) |
(length(number_1) + length(number_2) + length(number_3) == 12 & length(unique(combinations)) == 64)){
status <- "all possible"
}

# Add one to count every time the while loop runs
count <- count + 1

# Print the results of each while loop
print(paste0("length: ", length(unique(combinations))))
print(paste0("count: ", count))
}

# When the while loop stops, print all of the possible combinations
unique(combinations)

You can see a lot of other solutions to the phone pad interview question at Stack Overflow. You can also see the above solutions at GitHub.

Thanks for reading! This website took a great deal of time to create. If it was helpful to you, please show it by sharing with friends, liking, or tweeting! If you have any thoughts regarding this R code please post in the comments.

Fizz Buzz Interview Test in R

Apparently a common programming interview test is to have the candidate write a program that meets the following requirements:

• Print the numbers from 1 to 100
• When the number is a multiple of 3 print “Fizz” instead of the number
• When the number is a multiple of 5 print “Buzz instead of the number
• When the number is a multiple of both print “FizzBuzz”

I thought it would be fun to try this in R. My solution to the Fizz Buzz interview test in R is below. You can also see this code in my GitHub.

Create a Loop that Prints the Numbers from 1 to 100

Although some say to avoid loops in R in this case a loop seems like a good way to solve this problem. First let’s make a loop that just prints the numbers from 1 to 100:

# Print the numbers from 1 to 100

for (i in 1:100) {
print(i)
}

This produces the following (output cut off at 15 to save space):

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15

Have R Print “Fizz” for Multiples of 3

Now let’s add an if else statement that prints “Fizz” for multiples of three. Note that this solution uses the modulo command which calculates the remainder. In this case the value of i is divided by three and the remainder is produced:

# Print the numbers from 1 to 100
# For multiples of 3 print "Fizz"
i <- 1
for (i in 1:100) {
if(i %% 3 == 0) {print("Fizz")}
else print(i)
}

This produces the following (output cut off at 15 to save space):

 1
 2
 “Fizz”
 4
 5
 “Fizz”
 7
 8
 “Fizz”
 10
 11
 “Fizz”
 13
 14
 “Fizz”

Have R Print “Fizz” for Multiples of 3 and “Buzz” for Multiples of 5

Now we’ll add and else if command to tell R to print “Buzz” for multiples of five. Note that values of i that are multiples of both will print “Fizz” because that is the first command:

# Print the numbers from 1 to 100
# For multiples of 3 print "Fizz"
# For multiples of 5 print "Buzz"

for (i in 1:100) {
if (i %% 3 == 0) {print("Fizz")}
else if (i %% 5 == 0) {print("Buzz")}
else print(i)
}

This produces the following (output cut off at 15 to save space):

 1
 2
 “Fizz”
 4
 “Buzz”
 “Fizz”
 7
 8
 “Fizz”
 “Buzz”
 11
 “Fizz”
 13
 14
 “Fizz”

Have R Print “FizzBuzz” for Numbers that are Multiples of Both 3 and 5

Finally we’ll add a command at the beginning that tells R to print “FizzBuzz” for multiples of both 3 and 5:

# Print the numbers from 1 to 100
# For multiples of 3 print "Fizz"
# For multiples of 5 print "Buzz"
# For multiples of both print "FizzBuzz"

for (i in 1:100) {
if (i %% 3 == 0 & i %% 5 == 0) {print("FizzBuzz")}
else if (i %% 3 == 0) {print("Fizz")}
else if (i %% 5 == 0) {print("Buzz")}
else print(i)
}

This produces the following (output cut off at 15 to save space):

 1
 2
 “Fizz”
 4
 “Buzz”
 “Fizz”
 7
 8
 “Fizz”
 “Buzz”
 11
 “Fizz”
 13
 14
 “FizzBuzz”

If you’re interested in doing this “the R way” without a loop there is a vectorized solution here: http://librestats.com/2012/01/10/honing-your-r-skills-for-job-interviews/

Thanks to Revolution Analytics for Sponsoring Madison R Meetup Group!

Thanks to Revolution Analytics for sponsoring the MadR Madison R users meetup group! We really appreciate it. During a meeting we filled out the application and we were surprised not long after with a box of fun R gifts like a flying monkey , R themed t shirts, and stickers. We also received a \$100 grant. Thank you! R Baby Height Predictor

Not surprisingly, parents are interested in knowing what their future children will be like. One topic of interest is how tall their child will be as an adult. As you might expect, height is somewhat predictable. You can predict a child’s adult height with the parents’ heights and the baby’s gender. See http://www.mayoclinic.org/child-growth/expert-answers/faq-20057990 for more detail.

Once the baby is born you can do more accurate predictions using lookup tables but that’s beyond the scope of this post.

# What gender is the baby? Enter M or F.
gender <- "M"
# How tall is the mother in inches? Enter a number.
mother <- 64.5
# How tall is the father in inches? Enter a number.
father <- 70
# Use an if statement to create a correction of 5 if gender is male and
# -5 if gender is -5
if(gender=="M") correction <- 5 else
correction <- -5
# Calculate height by adding the mother's height, the father's height and
# the correction factor
height <- (mother + father + correction) / 2
# Create values that the user will understand
feet <- trunc(height / 12)
inches <- round(height - feet * 12, 0)
# Let the user know how tall their baby will be
print(paste("Your baby will be about ",feet," feet, ",inches," inches tall as an adult.",sep=""))

 "Your baby will be about 5 feet, 10 inches tall as an adult."

Calculate Pi in R

R has a built in function for pi but for pi day (3/14) I thought it would be fun to program R to calculate pi. I found a formula called Nilicantha’s formula:

# pi = 3 + 4/(2*3*4) – 4/(4*5*6) + 4/(6*7*8) – 4/(8*9*10) + 4/(10*11*12) – (4/(12*13*14) …

Here’s the code I wrote:

options(digits = 22) # 22 is max allowed
pi_calc <- 3
x <- 2
n <- 10000
for(i in 1:n) {
y <- x + 1
z <- x + 2
combine_with_pi_calc <- 4 / (x * y * z)
test <- i %% 2 == 0
if (isTRUE(test)) {
pi_calc <- pi_calc - combine_with_pi_calc
}
else {
pi_calc <- pi_calc + combine_with_pi_calc
}
x <- z
print(pi_calc)
}
# Compare to the pi constant included in R
# Matches out to the 12th digit
# I think the error is due to floating point, not the formula, but I'm not sure.
print(pi)

It works!

 3.141592653589537764702
 3.141592653590038697331
 3.141592653589537764702
 3.141592653590038253242
 3.141592653589537764702
 3.141592653590038253242
 3.141592653589538208792
 3.141592653590038253242
 3.141592653589538208792
>
> # Compare to the pi constant included in R
> # Matches out to the 12th digit
> print(pi)
 3.141592653589793115998

What do you think? Has anyone else written code to calculate pi in R?

Automated R Blogging (How To Capitalize Specific Letters in a String with R)

In the woRld of R blogging it can sometimes be fun to wRite with all the Rs capitalized. This is entertaining for both the author and the reader but not very efficient. It’s tough to remember to capitalize letters in the middle of the word and even if the writer does remember, it’s extra work to press the shift key. Instead, let’s automate the capitalization of Rs. Luckily, this is pretty easy in R:

# First, make an example blog post
data <- "Many times I want to write in r style but I never have the time to even though it makes the other users think I am rad."

# Now use gsub to convert r to R
data <- gsub("r", "R", data)

# Show the new and improved post
print(data)
 "Many times I want to wRite in R style but I neveR have the time to even though it makes the otheR useRs think I am Rad."

Calling for Presenters for the Madison R Meetup!

Want to present at the Madison R meetup or know someone who might? I’m looking for both short (5 to 30 minutes) and long presentations for future meetups. Short presentations will be grouped with other short presentations to fill up a meeting while longer presentations will have the time to themselves.

Any R related topic that others might find interesting or useful is welcome. Please contact me through the Meetup or through the rprogramming.net contact form if interested in presenting.

New Madison, WI R Programming UseRs Group (MadR)

Live in Madison, Wisconsin? Join the Madison R programming users group to learn more about R and contribute to the community. I just started it and am looking for members and presenters. You can find it here: http://www.meetup.com/MadR-Madison-R-Programming-UseRs-Group/ or through the link in the column to the right of this post. No events have been scheduled yet but something will be on the calendar soon.