3 Playing Game-A a Few Times

By now you know that Game-A involves rolling a (fair) die four times, and you win if you get at least one six.

Rolling 4 dice in Game version A

Figure 3.1: Rolling 4 dice in Game version A

You’ve also learned that we can write some code to play this game once, determining the winning status:

# playing Game-A once
set.seed(20)
die = 1:6
four_rolls = sample(die, size = 4, replace = TRUE)
win = any(four_rolls)
win
## [1] TRUE

3.1 Playing Game-A Five Times

We are ready to write code and use it to play Game-A five times

set.seed(133)

die = 1:6

game_1 = sample(die, size = 4, replace = TRUE)
game_2 = sample(die, size = 4, replace = TRUE)
game_3 = sample(die, size = 4, replace = TRUE)
game_4 = sample(die, size = 4, replace = TRUE)
game_5 = sample(die, size = 4, replace = TRUE)

# win (or lose)?
wins = c(
  "game_1" = any(game_1 == 6),
  "game_2" = any(game_2 == 6),
  "game_3" = any(game_3 == 6),
  "game_4" = any(game_4 == 6),
  "game_5" = any(game_5 == 6))
  
# number of wins
total_wins = sum(wins)
total_wins
## [1] 3
# proportion of wins
prop_wins = sum(wins) / 5
prop_wins
## [1] 0.6

As you can tell, the above code works, but there is a substantial amount of unnecessary repetition. Imagine copying-pasting the sample() command if we wanted to play Game-A 50 times, or 100 times, or 1000 times.

3.2 Using a for() loop

The above code generates the following five games (each game with 4 rolls)

To avoid repeating the same commands multiple times, we can take advantage of loops, for example a for() loop.

Instead of using individual vectors game_1, game_2, etc, we are going to use a matrix to store the rolls of all games. One option for this matrix is to initialize it in a way that rows correspond to games, while columns correspond to rolls:

Structure of output matrix with 5 rows and 4 columns.

Figure 3.2: Structure of output matrix with 5 rows and 4 columns.

The idea is to have an iterative process in which each iteration is associated to a game. In other words, at each iteration we play a single game, and we store the output of the rolls in the associated row of the matrix. Here’s how.

set.seed(133)

die = 1:6
number_games = 5

# initialize output matrix (full of zeros)
games = matrix(0, nrow = number_games, ncol = 4)

# each iteration corresponds to a single game
for (game in 1:number_games) {
  games[game, ] = sample(die, size = 4, replace = TRUE)
}

rownames(games) = paste0("game", 1:number_games)
colnames(games) = paste0("roll", 1:4)
games
##       roll1 roll2 roll3 roll4
## game1     1     6     4     1
## game2     5     1     1     6
## game3     2     5     5     4
## game4     2     6     6     1
## game5     4     1     1     1

Observe the calls of rownames() and colnames() to assign names to both the rows and the columns of the games matrix. In turn, the row and column names are created with paste0() to generate the necessary character vectors.

3.3 Playing Game-A 10 times

Now that we have our for() loop in place, we can easily increase the number of games. For instance, consider 10 games. Taking into account the preceding code chunk, all we have to do is change the value of number_games from 5 to 10.

set.seed(133)

die = 1:6
number_games = 10

# initialize output matrix
games = matrix(0, nrow = number_games, ncol = 4)

for (game in 1:number_games) {
  games[game, ] = sample(die, size = 4, replace = TRUE)
}

rownames(games) = paste0("game", 1:number_games)
colnames(games) = paste0("roll", 1:4)
games
##        roll1 roll2 roll3 roll4
## game1      1     6     4     1
## game2      5     1     1     6
## game3      2     5     5     4
## game4      2     6     6     1
## game5      4     1     1     1
## game6      4     3     4     2
## game7      6     3     1     3
## game8      4     2     1     1
## game9      1     6     2     1
## game10     5     1     6     5

As you can tell, we get a matrix games with 10 rows and 4 columns.

We still need to determine the status of each game: do we win? or do we lose?

Conceptually, we could write another for() loop to determine the status of each game: win or lose; something like this

# initialize (logical) vector
wins = logical(length = number_games)

for (game in 1:number_games) {
  wins[game] = any(games[game, ] == 6)
}
wins
##  [1]  TRUE  TRUE FALSE  TRUE FALSE FALSE  TRUE FALSE  TRUE  TRUE

What are we doing in the preceding loop? Simply put, we are applying the any() function to every row of matrix games to see if any of the row elements are equal to six. This is illustrated in the following diagram:

Diagram depicting the application of any() to all the rows of matrix games.

Figure 3.3: Diagram depicting the application of any() to all the rows of matrix games.

While there is nothing conceptually wrong with the above for() loop, we can take advantage of other functions in R to help us write code in a more compact way. Let’s learn about this topic in the next chapter.