library(tidyverse)
library(igraph)
Day 9
Advent of Code: Worked Solutions
Setup
Import libraries:
Read input from file:
<- scan(file = "../input/day09.txt", what = character(), quiet = TRUE) input
Convert input from plaintext to an integer matrix:
<- input |>
mtx str_split("") |>
list_c() |>
as.integer() |>
matrix(nrow = length(input), byrow = TRUE)
Part 1
Create shifted versions of our matrix to get the values above, below, to the left, and to the right of any given cell:
<- lag(mtx)
mtx_above <- lead(mtx)
mtx_below <- t(lag(t(mtx)))
mtx_left <- t(lead(t(mtx))) mtx_right
Find all low points:
<- (
low < mtx_above &
mtx < mtx_below &
mtx < mtx_left &
mtx < mtx_right
mtx
)
is.na(low)] <- TRUE low[
Compute the risk level of each low point:
sum(mtx[low] + 1)
Part 2
For each applicable point on the map, determine its smallest surrounding coordinate(s) where smoke will flow:
<- pmap(
neighbors list(mtx, mtx_left, mtx_right, mtx_above, mtx_below),
\(i, l, r, u, d) {<- c("I" = i, "L" = l, "R" = r, "U" = u, "D" = d)
dirs <- dirs[dirs == min(dirs, na.rm = TRUE)] |>
flow discard(is.na) |>
discard_at("I") |>
names()
if (i != 9) flow else character(0)
}|>
) enframe(name = "loc_id", value = "neighbor") |>
unnest_longer(neighbor) |>
mutate(
neighbor = case_match(neighbor,
"U" ~ loc_id - 1,
"D" ~ loc_id + 1,
"L" ~ loc_id - nrow(mtx),
"R" ~ loc_id + nrow(mtx)
) )
Convert list of neighbors to a graph:
<- neighbors |>
g pmap(~ c(..1, ..2)) |>
list_c() |>
make_graph()
For each low point, compute the size of its basin from its graph neighborhood:
<- components(g)$membership[which(low)]
basin_ids <- components(g)$csize[basin_ids] basin_size
Multiply together the sizes of the three largest basins:
|>
basin_size sort(decreasing = TRUE) |>
head(3) |>
prod()