<-
instructions read.table(here::here("2020", "day", "8", "input"),
col.names = c("instruction", "value"))
2020: Day 8
Setup
Part 1
Our programme gets stuck in an infinite loop. As well as keeping track of the accumulator, we need to keep track of where we’ve visited, and stop when we visit the same instruction twice. We use a data.frame()
rather than a tibble()
as the former is easier to index into.
We start with a pretty straight-forward loop, noting that at most it can run for one more than the number of instructions in the programme until it hits an instruction it’s already visited. We update row number to visit next and the accumulator as appropriate.
$visited <- 0
instructions
<- 1
row <- 0
accumulator
<- nrow(instructions)
num_rows
for (i in 1:(num_rows+1)) {
if (instructions[row, "visited"] != 0) break
# +1 on number of times the row is visited
"visited"] <- instructions[row, "visited"] + 1
instructions[row,
# case when the instruction is "acc"
if (instructions[row, "instruction"] == "acc") {
<- accumulator + instructions[row, "value"]
accumulator <- row + 1
row
}
# case when the instruction is "jmp"
else if (instructions[row, "instruction"] == "jmp") {
<- row + instructions[row, "value"]
row
}
# case when the instruction is "nop"
else if (instructions[row, "instruction"] == "nop") {
<- row + 1
row
}
}
accumulator
[1] 1915
Part 2: Fixing the programme
To break the loop, one of the nop
instructions in the programme should be a jmp
or vice versa. The plan is to swap these out one by one and check if the programme completes. It’s not a sophisticated approach, but it works fast enough (about a second).
First we note that the broken instruction must be one that we visited in Part 1. Also, an instruction of jmp
with a value of 0 will get us stuck in a one-line infinite loop, so we avoid that.
library(dplyr)
<- instructions %>%
rows_to_check mutate(row_id = row_number()) %>%
filter(visited != 0) %>%
filter(instruction != "acc") %>%
filter(!(instruction == "nop" & value == 0)) %>%
pull(row_id)
We have 93 instruction to check. We modify our code from Part 1 slightly, converting it into a function and returning a list with values completes
and accumulator
. completes
is FALSE
as soon as we visit a row twice and TRUE
if the number of our next row to visit is greater than the number of rows in the programme.
<- function(instructions) {
programme_completes
<- 1L
row <- 0
accumulator
<- nrow(instructions)
num_rows
for (i in 1:(num_rows+1)) {
if (instructions[row, "visited"] != 0) {
return(list(completes = FALSE, accumulator = accumulator))
}
# +1 on number of times the row is visited
"visited"] <- instructions[row, "visited"] + 1
instructions[row,
# case when the instruction is "acc"
if (instructions[row, "instruction"] == "acc") {
<- accumulator + instructions[row, "value"]
accumulator <- row + 1
row
}
else if (instructions[row, "instruction"] == "jmp") {
<- row + instructions[row, "value"]
row
}
else if (instructions[row, "instruction"] == "nop") {
<- row + 1
row
}
if (row > num_rows) {
return(list(completes = TRUE, accumulator = accumulator))
}
} }
We now loop over the rows we’ve identified to check, breaking the loop as soon as we find a programme that completes. Finally, we extract the accumulator value from the successful programme.
$visited <- 0
instructions
for (row in rows_to_check) {
# modify one row of the instructions,
# copying data frame so we don't have to modify it back
<- instructions
modified_instructions
ifelse(instructions[row, 1] == "jmp",
1] <- "nop",
modified_instructions[row, 1] <- "jmp")
modified_instructions[row,
# check if the modified programme completes
<- programme_completes(modified_instructions)
check_programme
if (check_programme$completes)
break
}
$accumulator check_programme
[1] 944
Session info
Toggle
─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.3.1 (2023-06-16)
os macOS Sonoma 14.0
system aarch64, darwin20
ui X11
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz Europe/London
date 2023-11-06
pandoc 3.1.1 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
quarto 1.4.466 @ /usr/local/bin/quarto
─ Packages ───────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
dplyr * 1.1.2 2023-04-20 [1] CRAN (R 4.3.0)
sessioninfo * 1.2.2 2021-12-06 [1] CRAN (R 4.3.0)
[1] /Users/ellakaye/Library/R/arm64/4.3/library
[2] /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library
──────────────────────────────────────────────────────────────────────────────