library(tidyverse)
library(unglue)Day 8
Advent of Code: Worked Solutions
Setup
Import libraries:
Read text input from file and parse into a dataframe of character operations and integer arguments:
input <- read_lines("../input/day08.txt") |>
unglue_data("{op} {arg}", convert = TRUE) |>
deframe()Part 1
Define a function to loop through the instructions in the input, break whenever an instruction is visited for a second time, and return the accumulator value at that time:
find_loop <- function(instructions) {
visited <- rep(FALSE, length(instructions))
acc <- 0
i <- 1
while (i <= length(instructions)) {
if (visited[i]) {
return(acc)
} else {
visited[i] <- TRUE
}
op <- names(instructions)[[i]]
arg <- instructions[[i]]
if (op == "nop") {
i <- i + 1
} else if (op == "acc") {
acc <- acc + arg
i <- i + 1
} else if (op == "jmp") {
i <- i + arg
}
}
return(NA)
}Run on puzzle input:
find_loop(input)Part 2
Swap each jmp and nop operation one-by-one and see which swap results in a valid output (no loop):
instr_mod <- map(
which(names(input) %in% c("jmp", "nop")),
\(idx) {
input |>
set_names(modify_at(
names(input),
idx,
~ case_match(.x, "jmp" ~ "nop", "nop" ~ "jmp")
))
}
)
idx_mod <- instr_mod |>
map_dbl(find_loop) |>
detect_index(is.na)Modify the find_loop function to run the instructions and return the final value of the accumulator:
run_instr <- function(instructions) {
acc <- 0
i <- 1
while (i <= length(instructions)) {
op <- names(instructions)[[i]]
arg <- instructions[[i]]
if (op == "nop") {
i <- i + 1
} else if (op == "acc") {
acc <- acc + arg
i <- i + 1
} else if (op == "jmp") {
i <- i + arg
}
}
return(acc)
}Run on the valid modified index:
run_instr(instr_mod[[idx_mod]])