# Libraries
library(tidyverse)
library(igraph)
# Read input from file
<- read_lines("../input/day22.txt", skip_empty_rows = TRUE) input
Day 22
Advent of Code: Worked Solutions
Setup
Part 1
Convert input to a grid board and a series of steps in the path:
<- input |>
board head(-1) |>
enframe(name = "row") |>
mutate(value = str_split(value, "")) |>
unnest(value) |>
mutate(col = row_number(), .by = row, .after = row) |>
filter(value %in% c(".", "#")) |>
mutate(id = row_number(), .before = everything())
<- input |>
path tail(1) |>
str_split_1("(?<=.)(?=[LR])") |>
as_tibble_col(column_name = "input") |>
mutate(
turn = case_match(str_extract(input, "L|R"),
"R" ~ 1,
"L" ~ -1,
.default = 0
),walk = parse_number(input),
)
Create a set of 2D lists by direction:
<- map(
vecs c(row = "row", col = "col"),
~ board |>
select({{ .x }}, id, value) |>
arrange(.data[[.x]]) |>
nest(vec = c(id, value)) |>
mutate(vec = map(vec, deframe)) |>
select(vec) |>
deframe()
)
<- \(x, n) c(tail(x, n), head(x, -n))
wrap_head <- \(x, n) c(tail(x, -n), head(x, n))
wrap_tail
<- c("row_pos", "col_pos", "row_neg", "col_neg")
dirs_2d
<- function(dir_vec, prv_dir, turn) {
next_dir which(dir_vec == prv_dir) + turn - 1) %% length(dir_vec)) + 1]
dir_vec[((
}
<- function(id_start, dir_start, n) {
walk_n <- str_extract(dir_start, "row|col")
dir_vec <- case_match(str_extract(dir_start, "pos|neg"),
dir_sign "pos" ~ 1,
"neg" ~ -1
)
<- board |>
vec_idx filter(id == id_start) |>
pull({{ dir_vec }})
<- vecs[[dir_vec]][[vec_idx]]
x <- which(names(x) == id_start)
idx
for (i in 1:n) {
<- (idx + dir_sign - 1) %% length(x) + 1
idx_next
if (x[idx_next] == "#")
break
else
<- idx_next
idx
}
as.numeric(names(x)[idx])
}
<- function(cell_id, dir_num) {
compute_pwd <- filter(board, id == cell_id)
final 1000 * final$row + 4 * final$col + unname(dir_num)
}
<- board |>
init_cell filter(value == ".") |>
pull(id) |>
min()
Run on puzzle input:
<- init_cell
cell <- "row_pos"
dir
for (i in 1:nrow(path)) {
<- dir
prv_dir <- cell
prv_cell
<- next_dir(dirs_2d, prv_dir, path$turn[i])
dir <- walk_n(cell, dir, path$walk[i])
cell
}
compute_pwd(cell, which(dirs_2d == dir) - 1)
[1] 164014
Part 2
Convert from row/col vectors to roll/pitch/yaw vectors:
<- 50
box_dim
"roll"]] <- pmap(
vecs[[list(
$row[1:box_dim],
vecs$row[1:box_dim + box_dim * 2] |>
vecsrev() |>
map(rev)
),~ c(..1, ..2)
)
"pitch"]] <- pmap(
vecs[[list(
$col[1:box_dim + box_dim],
vecs$row[1:box_dim + box_dim * 3] |>
vecsmap(rev)
),~ c(..1, ..2)
)
"yaw"]] <- pmap(
vecs[[list(
$row[1:box_dim + box_dim],
vecs$col[1:box_dim + box_dim * 2] |>
vecsmap(rev),
$col[1:box_dim] |>
vecsmap(rev)
),~ c(..1, ..2, ..3)
)
<- map(
coords_3d c(roll = "roll", pitch = "pitch", yaw = "yaw"),
~ vecs[[.x]] |>
map(~ as.numeric(names(.x))) |>
enframe(name = .x, value = "id") |>
unnest(id) |>
relocate(id)
|>
) reduce(partial(full_join, by = join_by(id)))
Create a new set of instructions for making left/right turns that depend on which box face is currently occupied:
<- list(
dirs_3d f1 = c("roll_pos", "pitch_pos", "roll_neg", "pitch_neg"),
f2 = c("roll_pos", "yaw_neg", "roll_neg", "yaw_pos"),
f3 = c("yaw_pos", "pitch_pos", "yaw_neg", "pitch_neg"),
f4 = c("roll_neg", "yaw_neg", "roll_pos", "yaw_pos"),
f5 = c("roll_neg", "pitch_pos", "roll_pos", "pitch_neg"),
f6 = c("pitch_neg", "yaw_neg", "pitch_pos", "yaw_pos")
|>
) map(partial(set_names, nm = c("row_pos", "col_pos", "row_neg", "col_neg")))
<- board |>
faces mutate(
face_row = ceiling(row / box_dim),
face_col = ceiling(col / box_dim)
|>
) arrange(id) |>
mutate(
box_face = cur_group_id(),
.by = c(face_row, face_col)
|>
) select(id, box_face)
<- board |>
board_3d left_join(coords_3d, join_by(id)) |>
left_join(faces, join_by(id))
Redefine the walk function to take roll/pitch/yaw directions:
<- function(id_start, dir_start, n) {
walk_n <- str_extract(dir_start, "roll|pitch|yaw")
dir_vec <- case_match(str_extract(dir_start, "pos|neg"),
dir_sign "pos" ~ 1,
"neg" ~ -1
)
<- board_3d |>
vec_idx filter(id == id_start) |>
pull({{ dir_vec }})
<- vecs[[dir_vec]][[vec_idx]]
x <- which(names(x) == id_start)
idx
for (i in 1:n) {
<- (idx + dir_sign - 1) %% length(x) + 1
idx_next
if (x[idx_next] == "#")
break
else
<- idx_next
idx
}
as.numeric(names(x)[idx])
}
Re-run the puzzle input:
<- init_cell
cell <- "roll_pos"
dir <- dirs_3d$f1
dir_vec
for (i in 1:nrow(path)) {
<- dir
prv_dir <- cell
prv_cell
<- dirs_3d[[board_3d$box_face[[prv_cell]]]]
dir_vec
<- next_dir(dir_vec, prv_dir, path$turn[i])
dir <- walk_n(cell, dir, path$walk[i])
cell
}
compute_pwd(cell, which(dir_vec == dir) - 1)
[1] 47525