# Libraries
library(tidyverse)
# Read input from file
<- read_lines("../input/day14.txt", skip_empty_rows = FALSE) input
Day 14
Advent of Code: Worked Solutions
Setup
Part 1
Convert the input text into a matrix:
<- input |>
mtx str_split("") |>
unlist() |>
matrix(nrow = length(input), byrow = TRUE)
From Reddit hints: can use matrix transforms and regex to make the tilting computations more efficient.
# For a set of string vectors, shift all rocks in them to the left.
<- function(str) {
shift repeat {
<- str_replace_all(str, "\\.O", "O\\.")
new
if (all(str == new))
return(str)
else
<- new
str
}
}
# Tilt the entire matrix in a given direction (N/S/W/E)
<- function(mtx, dir = 'N') {
tilt
if (dir %in% c('W', 'E'))
<- t(mtx)
mtx if (dir %in% c('S', 'E'))
<- apply(mtx, 2, rev)
mtx
# Split the matrix into columns, shift the rocks, and recombine
<- split(mtx, col(mtx)) |>
mtx map(str_flatten) |>
shift() |>
str_split("") |>
do.call(args = _, what = cbind)
if (dir %in% c('S', 'E'))
<- apply(mtx, 2, rev)
mtx if (dir %in% c('W', 'E'))
<- t(mtx)
mtx
mtx }
Tilt the matrix and sum up the load:
<- function(mtx) {
compute_load split(mtx, col(mtx)) |>
map(~ which(rev(.x) == "O")) |>
unlist() |>
sum()
}
|>
mtx tilt() |>
compute_load()
[1] 109661
Part 2
Look for a cycle, then jump ahead to the 1000000000th state
<- \(mtx) reduce(c('N', 'W', 'S', 'E'), tilt, .init = mtx)
cycle
# Initialize
<- mtx
cur <- list()
loop <- 0
i
# Loop through cycles until a repeating loop is found
repeat {
<- i + 1
i <- cycle(cur)
cur <- cur
loop[[i]]
if (any(duplicated(loop)))
break
}
# Compute the length of the cycle and its starting point
<- which(duplicated(loop) | duplicated(loop, fromLast = TRUE))
cycle_rep <- max(cycle_rep) - min(cycle_rep)
cycle_len <- min(cycle_rep)
cycle_start
# Compute an equivalent index to find the state at the 1000000000th cycle
<- (1000000000 - cycle_start) %% cycle_len + cycle_start
idx
|>
loop[[idx]] compute_load()
[1] 90176