Day 4

Advent of Code: Worked Solutions

About
Date

December 4, 2021

Setup

Import libraries:

library(tidyverse)

Read input from file:

# List of drawn numbers
drawn <- scan("../input/day04.txt", nlines = 1, sep = ",", quiet = TRUE)

# Set of bingo boards
boards <- read_table("../input/day04.txt", skip = 2, col_names = FALSE) |> 
  group_split(cumsum(row_number() %% 5 == 1), .keep = FALSE) |> 
  map(~ unname(as.matrix(.x)))

Part 1

For all bingo boards, determine the time at which each number on their card is drawn.

filled <- imap_dfr(boards, \(board, board_id) {
  imap_dfr(drawn, \(num, idx) {
    which(board == num, arr.ind = TRUE) |> 
      as_tibble() |> 
      mutate(
        time = idx, 
        board_id = board_id
      )
  })
})

For each board, determine the time at which each “wins” by achieving a full row or column:

wins <- map_dfr(c("row", "col"), \(dim) {
  filled |> 
    summarize(n = n(), time = max(time), .by = all_of(c("board_id", dim))) |> 
    rename(dim_value = {{ dim }}) |> 
    mutate(dim_name = dim) |> 
    filter(n == 5)
}) |> 
  summarize(time = min(time), .by = board_id)

Define a function to score a board at the time of its win:

score <- function(board_id, time_win) {
  
  board      <- boards[[board_id]]
  nums_drawn <- drawn[1:time_win]
  unmarked   <- board[!(board %in% nums_drawn)]
  score      <- sum(unmarked) * tail(nums_drawn, 1)

  return(score)
}

Compute the final score of the first board to win:

first_winner <- slice_min(wins, time)

score(first_winner$board_id, first_winner$time)

Part 2

Compute the final score of the last board to win:

last_winner <- slice_max(wins, time)

score(last_winner$board_id, last_winner$time)