Reputation: 21
I wonder if anyone could help me to create a russian roulette game in R? I'm a total novice at R and at writing code in general. I would be very grateful for your help!
The game is played with a revolver equipped with a rotatable magazine of six shots. The revolver is loaded with one shot. The first duellist, A, rotates the magazine at random, points the revolver at his head and presses the trigger. If, afterwards, he is still alive, he hands the revolver to the other duellist, B, who acts in the same way as A. The players shoot alternately in this manner, until a shot goes off.
All I (with help) have come up with so far is:
shot<-runif(1,min=0,max=1)
killed<-runif(1,min=0,max=1/6)
roulette<-function()
{
while (shot!=killed)
{
shot <- runif(1,min=0,max=1)
print("click")
if (shot<killed)
break
}
{
print ("Dead")
}
}
for (i in 1:5)
{
roulette()
}
How do I count the number of times A or B has been killed in e g 1000 games? Some variable which can switch between A and B and then store the results in a list?
Upvotes: 1
Views: 1630
Reputation: 4169
I was looking at another post earlier this morning about a more complex Russian Roulette game in R, and decided to make a function for a simple version. In your example, you have "shuffling" because the chamber is spun before each turn.
RR <- function(PLAYERS, S = 6){
D <- 0
i <- 0
while(D != 1){
P <- sample(c(1, rep(0, times = S-1)))[1]
i <- i + 1
if(P == 1){
D <- 1
}
}
L <- rep(PLAYERS, length.out = i)[i]
L
}
In this function the while
argument is utilized to play rounds until someone wins; S
is the amount of chambers in the gun, and is set to 6 as default to make this a 6-shooter, D
is coding whether a player has died (1) or not (0), i
is the round of the game, P
is the random position of the bullet in the chamber, and if P = 1 (the bullet is in the first chamber after spinning), the player dies and the game is over. The loser (L
) is assigned and printed.
It appears that Clint Eastwood and John Wayne fancy a game...
> PLAYERS <- c("Eastwood", "Wayne")
> RR(PLAYERS)
[1] "Wayne"
But what happens over 10000 games?
> n <- 10000
> RRres <- rep(NA, times = n)
>
> for(i in 1:n){
+ RRres[i] <- RR(PLAYERS)
+ }
>
> table(RRres)
RRres
Eastwood Wayne
5393 4607
It looks like Clint shouldn't feel so lucky himself... but that's because he is always going first: there is an advantage in going last when you shuffle the chamber, because if the player(s) before you die, you don't play - it's more likely that a game will be over in few rounds than in many (Probability that a given round [n] results in the killshot = (1/6) * ((5/6)^n), where 1/6 is the risk of shuffling on to the loaded chamber, and (5/6)^n is the probability that someone already lost).
Therefore, you might want to randomize the order of players in each game using the sample
function:
> for(i in 1:n){
+ RRres[i] <- RR(sample(PLAYERS))
+ }
>
> table(RRres)
RRres
Eastwood Wayne
5017 4983
Note that this function works for any amount of players (e.g. 26 players):
> for(i in 1:n){
+ RRres[i] <- RR(sample(LETTERS[1:26]))
+ }
>
> table(RRres)
RRres
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
396 362 378 368 373 388 383 398 390 372 379 382 395 393 377 389 381 386 375 379 375 382 379 430 393 397
Upvotes: 0
Reputation: 48
You can use the while statement and count the number of iterations.
Odd number of shots fired = A dies, even number of shots fired = B dies
n <- 1000
outcomes <- cbind(rep("click",n),rep("click",n),numeric(length=n),numeric(length=n))
colnames(outcomes) <- c("finalA","finalB","nClickA","nClickB")
for (i in 1:nrow(outcomes)){
shot<-runif(1,min=0,max=1) #first shot
count <- 1
while (shot > 1/6) { #chance of dying is 1/6, so every 0 < shot < 1/6
#will be considered "death"
shot <- runif(1,min=0,max=1) #if not dead, shoot again
count <- count + 1 #and count the iterations
}
#replace "click" by "dead" for either A or B
ifelse ((count %% 2) > 0, #if count is odd number = A killed, else: B killed
(outcomes[i,1] <- "dead"), #replace the "click"s in outcomes matrix
(outcomes[i,2] <- "dead"))
#count and insert the number of clicks for each player
#if count = odd number, both had (count/2)-1 clicks
nclick <- count- 1 #the number of clicks is always the number of triggerpulls minus 1
if ((nclick %% 2) == 0) {outcomes[i,3:4] <- nclick/2
#if nclick is even number, both A and B took (nclick/2) clicks
} else {
outcomes[i,3] <- nclick/2+0.5
outcomes[i,4] <- nclick/2-0.5}
#if nclick is odd number, A took one click more than B
}
outcomes <- as.data.frame(outcomes)
table(outcomes$finalA)
table(outcomes$finalB)
Edit: If the probability of dying is not the same for each A and B, you could include an if-statement with different death probabilities inside the while loop, which will terminate once either A or B dies (death=TRUE
).
shot <- runif(1,min=0,max=1) #first shot
count <- 1
death <- logical(length=1) #new object needed to terminate the while-loop
if (shot < 0.6) {death <- TRUE} #A is already dead with p=.60
while (death != TRUE) { #if A survived the first trigger-pull, start while-loop
if (count %% 2 == 1) { #if count is odd, it's B's turn
shot <- runif(1,min=0,max=1) #next trigger-pull
if (shot < 0.8) {death <- TRUE} #B's probability of dying is .80
count <- count + 1
} else { #if count is even, it's A's turn again
shot <- runif(1,min=0,max=1)
if (shot < 0.6) {death <- TRUE}
count <- count +1
} #and this loop goes on until death = TRUE
}
Edit: What if the bullets are in adjacent chambers? If the bullets are in adjacent chambers, there are six possibile positions, two covering each chamber. First trigger-pull has p(death)=2/6. If no shot was fired, we know neither of the two bullet positions was true, to next triggerpull has p(death)=1/4, and so on.
count <- 1
k <- 5
death <- sample(c(T,T,F,F,F,F)[1:k],1)
while (death != TRUE){k <- k-1
death <- sample(c(T,F,F,F)[1:k],1)
count <- count +1}
Upvotes: 1
Reputation: 491
I understand the model to be "keep trading the gun back and forth until numshots number of shots are fired". I modeled the loaded chamber like the roll of a die, setting "6" to be the fatal roll
roulette <- function(numshots=1000){
killed = 6 # fatal face on a die
killshots = 0
won = 0
i = 0
while (killshots < numshots){
shot = sample(1:6, size=1, replace=T) # rolling a die
i = i + 1 # keep track of even or odd # of tries
if ( (shot == killed) ){
killshots = killshots + 1
if (i%%2 == 1){
won = won + 1
}
}
}
return(data.frame(A = won, B = numshots-won))
}
> roulette()
A B
1 502 498
Upvotes: 1