# Libraries
library(tidyverse)
# Read input from file
<- read_lines("../input/day06.txt", skip_empty_rows = TRUE) input
Day 6
Advent of Code: Worked Solutions
Setup
Part 1
# Guard functions --------------------------------------------------------------
<- c("^", ">", "v", "<")
guards <- c(tail(guards, -1), head(guards, 1))
guard_shift
<- function(cur) guard_shift[guards == cur]
rotate_guard
<- function(char) {
guard_dir case_match(char,
"^" ~ matrix(c(-1, 0), nrow = 1),
">" ~ matrix(c( 0, 1), nrow = 1),
"v" ~ matrix(c( 1, 0), nrow = 1),
"<" ~ matrix(c( 0, -1), nrow = 1)
)
}
<- function(coord, mtx) {
in_bounds between(coord[1], 1, nrow(mtx)) & between(coord[2], 1, ncol(mtx))
}
<- function(mtx) {
map_path
# Initiate guard's starting position and direction
<- keep(mtx, ~ .x %in% guards)
cur_char <- which(mtx == cur_char, arr.ind = TRUE)
cur_coord <- guard_dir(cur_char)
cur_dir
# As long as the guard is in bounds, iteratively update its coords and direction
repeat {
<- cur_coord + cur_dir
next_coord
# If next step is out-of-bounds, update matrix and exit
if (!in_bounds(next_coord, mtx)) {
<- "X"
mtx[cur_coord] break
}# If next step is an obstacle, rotate the guard
else if (mtx[next_coord] == '#') {
<- rotate_guard(cur_char)
cur_char <- guard_dir(cur_char)
cur_dir
}# Otherwise advance the guard forward
else {
<- "X"
mtx[cur_coord] <- next_coord
cur_coord
}
}
mtx }
# Convert input into a matrix
<- input |>
mtx str_split("") |>
unlist() |>
matrix(nrow = length(input), byrow = TRUE)
# Map the guard's path
<- map_path(mtx)
guard_path
# Count distinct positions visited
sum(guard_path == "X")
Part 2
Change the path mapping function to test for loops
<- function(mtx) {
path_loops
# Initiate guard's starting position and direction
<- keep(mtx, ~ .x %in% guards)
cur_char <- which(mtx == cur_char, arr.ind = TRUE)
cur_coord <- guard_dir(cur_char)
cur_dir <- matrix("", nrow(mtx), ncol(mtx))
path_hist
# As long as the guard is in bounds, iteratively update its coords and direction
repeat {
<- cur_coord + cur_dir
next_coord
# Check if the guard is looping or if they have left the area
if (str_detect(path_hist[cur_coord], fixed(cur_char)))
return(TRUE)
else if (!in_bounds(next_coord, mtx))
return(FALSE)
# If next step is an obstacle, rotate the guard
else if (mtx[next_coord] == '#') {
# Update path history
<- str_c(path_hist[cur_coord], cur_char)
path_hist[cur_coord] # Update guard
<- rotate_guard(cur_char)
cur_char <- guard_dir(cur_char)
cur_dir
}# Otherwise advance the guard forward
else {
# Update path history
<- str_c(path_hist[cur_coord], cur_char)
path_hist[cur_coord] # Update guard
<- next_coord
cur_coord
}
} }
# Create a variation of the map for each possible obstacle location
<- which(guard_path == "X" & !(mtx %in% guards))
obstacles
# Test each obstacle location for loops and sum result
|>
obstacles map(~ replace(mtx, .x, "#")) |>
map_lgl(path_loops) |>
sum()