# Libraries
library(tidyverse)
# Read input from file
input <- read_lines("../input/day04.txt", skip_empty_rows = FALSE)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:
cards <- input |>
# 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)Part 2
Create a reference table of the outputs received for each winning card:
rewards <- cards |>
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:
collect_reward <- \(inventory, i) inventory + inventory[[i]] * rewards[[i]]
reduce(1:nrow(cards), collect_reward, .init = rep(1, nrow(cards))) |>
sum()