# Libraries
library(tidyverse)
library(igraph)
# Read input from file
<- read_lines("../input/day18.txt", skip_empty_rows = TRUE) |>
input ::unglue_data(patterns = "{col},{row}", convert = TRUE) |>
ungluemutate(byte_num = row_number())
<- 70 maxdim
Day 18
Advent of Code: Worked Solutions
Setup
Part 1
# Fill out the full grid with the provided dimensions
<- input |>
grid complete(col = 0:maxdim, row = 0:maxdim) |>
mutate(id = row_number(), .before = everything()) |>
# Define the graph edges (cell borders) between vertices (cells)
mutate(edge_w = map2(id, lag(id), ~ c(.x, .y)), .by = row) |>
mutate(edge_n = map2(id, lag(id), ~ c(.x, .y)), .by = col)
# Define the IDs of the start and end vertices
<- grid |> filter(row == 0 & col == 0) |> pull(id)
start <- grid |> filter(row == maxdim & col == maxdim) |> pull(id) exit
Convert the grid to a graph and count the steps from the start to the exit:
<- function(grid, start, exit, num_bytes) {
compute_num_steps
|>
grid
# Flag and remove any graph edges between corrupted cells
mutate(corrupted = replace_na(byte_num <= num_bytes, FALSE)) |>
mutate(edge_w = case_when(!corrupted & !lag(corrupted) ~ edge_w), .by = row) |>
mutate(edge_n = case_when(!corrupted & !lag(corrupted) ~ edge_n), .by = col) |>
# Pull graph edges
select(edge_w, edge_n) |>
pivot_longer(everything()) |>
pull(value) |>
discard(is.null) |>
unlist() |>
# Convert to a graph
make_graph(n = max(grid$id), directed = FALSE) |>
# Count the steps from the start to the exit
distances(start, exit) |>
as.list() |>
unlist()
}
Run puzzle input:
compute_num_steps(grid, start, exit, 1024)
[1] 340
Part 2
Loop through different byte values to find the first byte that blocks the path:
# Initialize byte counts
<- max(grid$byte_num, na.rm = TRUE)
max_bytes <- 1024
max_walkable <- max_bytes
min_unwalkable <- round(mean(c(max_walkable, min_unwalkable)))
num_bytes
# Loop through bytes, a half at a time
while (min_unwalkable - max_walkable > 1) {
<- compute_num_steps(grid, start, exit, num_bytes)
num_steps
if (is.infinite(num_steps))
<- num_bytes
min_unwalkable else
<- num_bytes
max_walkable
<- round(mean(c(max_walkable, min_unwalkable)))
num_bytes }
Get the coordinates of the first byte that blocks the path:
|>
grid filter(byte_num == min_unwalkable) |>
mutate(coord = str_c(col, row, sep = ",")) |>
pull(coord)
[1] "34,32"