# Libraries
library(tidyverse)
# Read input from file
<- read_lines("../input/day21.txt", skip_empty_rows = TRUE) |>
input ::unglue_data(
ungluepatterns = c(
"{monkey}: {input_1} {operation} {input_2}",
"{monkey}: {number}"
),convert = TRUE
)
Day 21
Advent of Code: Worked Solutions
Setup
Part 1
Iteratively apply each monkey-to-monnkey operation until complete:
<- input |>
numbers select(monkey, number) |>
deframe()
<- input |>
eqns filter(!is.na(operation)) |>
select(-number)
<- function(numbers, eqns) {
compute_monkeys repeat {
<- eqns |>
new_values mutate(
value_1 = numbers[input_1],
value_2 = numbers[input_2]
|>
) drop_na(value_1, value_2) |>
mutate(output = pmap_dbl(
list(operation, value_1, value_2),
~ get(..1)(..2, ..3)
|>
)) select(monkey, output) |>
deframe()
if (length(new_values) == 0) {
break
else {
} names(new_values)] <- new_values
numbers[<- filter(eqns, !(monkey %in% names(new_values)))
eqns
}
}
numbers }
Run on puzzle input:
compute_monkeys(numbers, eqns) |>
keep_at("root") |>
format(scientific = FALSE)
root
"87457751482938"
Part 2
# Replace 'humn' number with NA and re-compute known equation values
<- compute_monkeys(
modified_numbers modify_at(numbers, "humn", ~ NA),
mutate(eqns, operation = if_else(monkey == "root", "==", operation))
)
<- eqns |>
monkey_funcs
# Reformat equations
mutate(operation = if_else(monkey == "root", "==", operation)) |>
mutate(
value_1 = modified_numbers[input_1],
value_2 = modified_numbers[input_2],
const = unname(coalesce(value_1, value_2)),
xposn = if_else(is.na(value_1), 1, 2),
input = if_else(is.na(value_1), input_1, input_2),
|>
) filter(is.na(value_1) | is.na(value_2)) |>
# Convert each operation into an inverse function
mutate(
f = pmap(list(operation, const, xposn), \(op, const, xposn) {
if (op == "+") partial(`-`, ... = , const)
else if (op == "*") partial(`/`, ... = , const)
else if (op == "-" & xposn == 1) partial(`+`, ... = , const)
else if (op == "/" & xposn == 1) partial(`*`, ... = , const)
else if (op == "-" & xposn == 2) partial(`-`, const, ... = )
else if (op == "/" & xposn == 2) partial(`/`, const, ... = )
}),|>
) select(output = monkey, f, input, const)
# Initiate starting monkey value at the root monkey
<- filter(monkey_funcs, output == "root")
cur_monkey <- cur_monkey$const
cur_value <- cur_monkey$input
next_monkey
# Compute function inverse for each monkey until "humn" is reached
while (next_monkey != "humn") {
<- filter(monkey_funcs, output == next_monkey)
cur_monkey <- cur_monkey$f[[1]](cur_value)
cur_value <- cur_monkey$input
next_monkey
}
# View final input needed to achieve equality
|>
cur_value format(scientific = FALSE)
[1] "3221245824363"