To install `mistlecode` yourself, run `devtools::install_github('guslipkin/mistlecode')`.
Also loading: cipheR data.table dplyr purrr slider stringr tidyverse
2022-11: Monkey in the Middle
Oh no. I’m going to bed.
Part 1
This was so much fun! I dipped my toes into S3 classes, made a useful function factory, and did some recursion. I had a bit of trouble making sure my list of monkeys was getting passed around properly and returned because loops can’t change objects in the global environment. That said, I have a bad feeling about part 2.
operation <- function(op, val) {
function(old) {
if (val == "old") { val <- as.integer(old) }
else { val <- as.integer(val) }
if (op == "*") { val <- old * val }
else if (op == "+") { val <- old + val }
return(val)
}
}
new_monkey <- function(dt, x) {
name <- str_extract(dt[1,"dt"], "\\d+")
items <-
str_split(dt[2,"dt"], ":|,", simplify = TRUE)[1,-1] |> as.numeric()
opp <-
str_split(dt[3, "dt"], "=", simplify = TRUE)[1,2] |>
str_match(" (new|old) (\\+|\\-|\\*|\\/) (old|\\d+)")
op_op <- opp[1,3]
op_num <- ifelse(opp[1,4])
op <- operation(op = opp[1,3], val = opp[1,4])
test <- str_extract(dt[4,"dt"], "\\d+") |> as.integer()
case_true <- str_extract(dt[5,"dt"], "\\d+")
case_false <- str_extract(dt[6,"dt"], "\\d+")
x <- list(
"name" = name,
"items" = items,
"operation" = op,
"test" = test,
"case_true" = case_true,
"case_false" = case_false,
"inspections" = 0
)
structure(x, class = "monkey")
}
monkeys <-
lapply(unique(dt$monkey), \(m) {
new_monkey(dt[dt$monkey == m,], m)
})
names(monkeys) <- sapply(monkeys, \(m) m$name)
process_items <- function(item, monkey, these_monkeys) {
if (is.na(monkey$items[item]) |
item > length(monkey$items)) { return(these_monkeys) }
worry_level <- monkey$operation(monkey$items[item])
worry_level <- floor(worry_level / 3)
if (worry_level %% monkey$test == 0) {
case_true <-
c(these_monkeys[[monkey$case_true]]$items, worry_level)
these_monkeys[[monkey$case_true]]$items <-
case_true[!is.na(case_true)]
} else {
case_false <-
c(these_monkeys[[monkey$case_false]]$items, worry_level)
these_monkeys[[monkey$case_false]]$items <-
case_false[!is.na(case_false)]
}
process_items(item + 1, monkey, these_monkeys)
}
process_monkey <- function(i, these_monkeys) {
if (i == length(monkeys) + 1) { return(these_monkeys) }
monkey <- these_monkeys[[i]]
these_monkeys <- process_items(1, monkey, these_monkeys)
monkey$inspections <-
sum(monkey$inspections, length(monkey$items), na.rm = TRUE)
monkey$items <- as.numeric(NA)
these_monkeys[[i]] <- monkey
process_monkey(i + 1, these_monkeys)
}
round <- function(these_monkeys, round) {
if (round == round_max + 1) { return(these_monkeys) }
these_monkeys <- process_monkey(1, these_monkeys)
round(these_monkeys, round + 1)
}
Part 2
I want to scream. I submitted my answer just to see and it’s right, even though the test input was wrong. I could’ve submitted yesterday 😭 So many hours devoted to these monkeys for nothing…
I figured out the worry_level %% prod(tests)
thing pretty quick after part 1, but it took a full day because the test input never lined up, even if I got super close. I still want to figure out why that is, but for now I’m just happy to have the star.
process_items <- function(item, monkey, these_monkeys) {
if (is.na(monkey$items[item]) |
item > length(monkey$items)) { return(these_monkeys) }
worry_level <- monkey$operation(monkey$items[item])
case <- (worry_level %% monkey$test) == 0
worry_level <- worry_level %% prod(tests)
if (case) {
case_true <-
c(these_monkeys[[monkey$case_true]]$items, worry_level)
these_monkeys[[monkey$case_true]]$items <-
case_true[!is.na(case_true)]
} else {
case_false <-
c(these_monkeys[[monkey$case_false]]$items, worry_level)
these_monkeys[[monkey$case_false]]$items <-
case_false[!is.na(case_false)]
}
process_items(item + 1, monkey, these_monkeys)
}
m <- monkeys
tests <- sapply(m, \(m) m$test)
round_max <- 1
i <- 1
while (i <= 10000) {
m <- process_monkey(1, m)
i <- i + 1
}
sapply(m, \(m) m$inspections) |>
sort(decreasing = TRUE) |>
head(2) |>
prod()
[1] 35270398814