# Libraries
library(tidyverse)
# Read input from file
<- read_lines("../input/day04.txt", skip_empty_rows = FALSE) input
Day 4
Advent of Code: Worked Solutions
Setup
Part 1
Reformat input into lists of winning numbers vs chosen numbers for each card, then score each card:
<- input |>
cards
# Reformat as a data frame of winning vs chosen numbers per card
str_remove("Card .*:") |>
enframe(name = "card_id", value = "txt") |>
separate(txt, into = c("winning", "chosen"), sep = "\\|") |>
mutate(across(c(winning, chosen), \(vec) {
|>
vec trimws() |>
str_split("\\s+") |>
map(parse_number)
|>
}))
# Count the number of overlapping chosen & winning numbers per card:
mutate(
n_common = map2_int(winning, chosen, ~ length(intersect(.x, .y))),
score = if_else(n_common == 0, 0, 2^(n_common - 1))
)
Sum all cards’ scores:
sum(cards$score)
[1] 24542
Part 2
Create a reference table of the outputs received for each winning card:
<- cards |>
rewards mutate(
reward_start = card_id + 1,
reward_end = pmin(card_id + n_common, max(card_id)),
reward = pmap(list(reward_start, reward_end, n_common), \(start, end, n) {
if (n == 0)
rep(0, nrow(cards))
else
rep(0, nrow(cards)) |>
modify_at(.at = seq(start, end), ~1)
})|>
) pull(reward)
Loop through each card in the inventory, accumulate rewards at each step, then sum the final total number of cards:
<- \(inventory, i) inventory + inventory[[i]] * rewards[[i]]
collect_reward
reduce(1:nrow(cards), collect_reward, .init = rep(1, nrow(cards))) |>
sum()
[1] 8736438