Anna
Anna

Reputation: 21

Creating a Russian roulette game in R

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

Answers (3)

rg255
rg255

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).

enter image description here

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

Jonathan S
Jonathan S

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

cumin
cumin

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

Related Questions