Flipping Coins Until Some Event Happens

Imagine I have 3 coins .

  • Coin 1: Probability of Heads = 0.5, Reward Heads = +1, Reward Tails = -1
  • Coin 2: Probability of Heads = 0.8, Reward Heads = 0.2, Reward Tails = -0.1
  • Coin 3 Probability of Heads = 0.3 Reward Heads = + 3, Reward Tails = -5

Now, imagine two players (player 1 always starts) take turns flipping random coins while tallying their score (player 1 always starts) - the first player to reach reward = + 10 wins.

My Question: I want to simulate 5 games that contain the turn-by-turn details of both players until a winner is reached.

First, I defined the coin information:

# Define coin properties
coin1 <- list(prob = 0.5, reward_heads = 1, reward_tails = -1)
coin2 <- list(prob = 0.8, reward_heads = 0.2, reward_tails = -0.1)
coin3 <- list(prob = 0.3, reward_heads = 3, reward_tails = -5)

Next, I defined a function to flip a coin

# Define function to flip a coin 
flip_coin <- function(coin) {
  if (runif(1) < coin$prob) {
    return(coin$reward_heads)
  } else {
    return(coin$reward_tails)
  }
}

Then, I defined the initial data frame to store the game results:

game_log <- data.frame(turn_no = numeric(), 
                       current_player_turn = character(), 
                       coin_chosen = character(),
                       player_1_current_score = numeric(), 
                       player_2_current_score = numeric(),
                       stringsAsFactors = FALSE)
player_names <- c("player 1", "player 2")
current_player <- player_names[1]
# Set up initial scores and game state
player_scores <- c(0, 0)
game_state <- list(current_player = 1, game_log = game_log)

Finally, I tried to write a function to simulate a single game - this would involve steps such as: creating a WHILE LOOP until cumulative score of any player is > 10, select a random coin at each turn, flipping the selected coin, updating scores and alternating between players

play_game <- function() {
game_no = n
  # Play the game until a player reaches a score of +10
  while (max(player_scores) < 10) {
    # Choose a coin at random
    coin_choice <- sample(c("coin1", "coin2", "coin3"), 1)
    
    # Flip the chosen coin
    coin_result <- flip_coin(get(coin_choice))
    
    # Update the current player's score
    player_scores[current_player] <- player_scores[current_player] + coin_result
    
    # Log the current turn's information
    turn_info <- data.frame(turn_no = nrow(game_log) + 1,
                            current_player_turn = current_player,
                            coin_chosen = coin_choice, game_no = n,
                            player_1_current_score = player_scores[1],
                            player_2_current_score = player_scores[2])
    game_log <- rbind(game_log, turn_info)
    
    # Switch to the other player's turn
    current_player <- ifelse(current_player == 1, 2, 1)
  }
  
  # Return the game log
  return(game_log)
}

But I get an error:

Error in while (max(player_scores) < 10) { : 
  missing value where TRUE/FALSE needed

Had this worked, I would have then replicated 5 games like this:

n_iterations <- 5
result <- lapply(1:n_iterations, play_game, n = n_rows)
result <- do.call(rbind, result)

Can someone please show me how to do this?

Thanks!

I'm getting an error that you dont mention; which makes me think you set n <- something in your environment as you have code that says game_no = n and this doesn't coincide with anything for me.
I think your code shows confusion in regards to player_scores and player_names; because initially you have player_names as strings, and then later you ifelse the current_player based on them being numbers; and this causes Na's into player_scores which then cause your if(max(player_scores) <10 line to fail.
perhaps simplify by omitting the strings and having the names only be c(1,2) i.e. 1:2 would be a way forward.

1 Like

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.