# Libraries
library(tidyverse)
library(bit64)
library(memoise)
# Read input from file
<- read_lines("../input/day22.txt", skip_empty_rows = TRUE) |>
input as.numeric()
Day 22
Advent of Code: Worked Solutions
Setup
Part 1
Define custom bitwise XOR function, needed to handle large integers:
<- function(x, y) {
bitwXor64 <- as.bitstring(as.integer64(x))
x <- as.bitstring(as.integer64(y))
y
map2_chr(
|> str_split("") |> map(as.integer),
x |> str_split("") |> map(as.integer),
y ~ base::xor(.x, .y) |>
as.integer() |>
str_c(collapse = "")
|>
) structure(class = "bitstring") |>
as.integer64() |>
as.numeric()
}
Define the algorithm for producing a sequence of “secret” numbers:
<- memoise::memoise(\(a, b) bitwXor64(a, b))
mix <- \(x) x %% 16777216
prune
<- function(x) {
secret_alg <- prune(mix(x, x * 64))
x1 <- prune(mix(x1, floor(x1 / 32)))
x2 <- prune(mix(x2, x2 * 2048))
x3 return(x3)
}
<- function(init, len) {
secret_seq <- list(init)
out for (i in 2:len) {
<- secret_alg(pluck(out, i - 1))
out[[i]]
}
out }
Run puzzle input:
<- secret_seq(input, len = 2001)
secret_nums
|>
secret_nums tail(n = 1) |>
unlist() |>
sum()
[1] 20401393616
Part 2
# Convert sequences to a data frame by buyer and time
<- secret_nums |>
diffs imap_dfr(\(x, idx) tibble(time = idx, secret_number = x)) |>
mutate(
buyer_id = row_number(),
.by = time
|>
) mutate(
# Get the price at each time by taking the ones digit of each secret number
price = secret_number %% 10L,
# Compute the difference in price at the current time vs the previous time
diff = price - lag(price),
# Compute the sequence of 4 price changes preceeding the current price
lag1 = lag(diff, n = 1L),
lag2 = lag(diff, n = 2L),
lag3 = lag(diff, n = 3L),
diff_seq = str_c(lag3, lag2, lag1, diff, sep = ","),
.by = buyer_id
|>
) arrange(buyer_id, time)
# For each price change seq, compute the bananas you will get from each buyer:
<- diffs |>
bananas_by_seq filter(!is.na(diff_seq)) |>
summarize(
bananas = head(price, 1),
.by = c(buyer_id, diff_seq)
)
# Find the most advantageous sequence:
|>
bananas_by_seq summarize(bananas = sum(bananas), .by = diff_seq) |>
slice_max(bananas) |>
pull(bananas)
[1] 2272