diff --git a/2024/R/day15.qmd b/2024/R/day15.qmd
index a47d7e2..4f2b961 100644
--- a/2024/R/day15.qmd
+++ b/2024/R/day15.qmd
@@ -129,4 +129,140 @@ mtx |>
sum()
```
+## Part 2
+
+Widen the map:
+
+```{r}
+# Convert WH input text to a matrix
+mtx <- input_wh |>
+ str_replace_all("#", "##") |>
+ str_replace_all("O", "[]") |>
+ str_replace_all("\\.", "..") |>
+ str_replace_all("@", "@.") |>
+ str_split("") |>
+ matrix() |>
+ unlist() |>
+ matrix(byrow = TRUE, nrow = length(input_wh))
+```
+
+Define functions to move boxes around the map:
+
+```{r}
+
+get_box_coords <- function(mtx, box_num) {
+ as_tibble(which(mtx == box_num, arr.ind = TRUE))
+}
+
+get_next_coords <- function(cur_coords, dir = c("<", "^", ">", "v")) {
+ cur_coords |>
+ mutate(
+ row = row + case_match(dir, "^" ~ -1, "v" ~ 1, .default = 0),
+ col = col + case_match(dir, "<" ~ -1, ">" ~ 1, .default = 0),
+ )
+}
+
+get_next_chrs <- function(mtx, cur_coords, dir = c("<", "^", ">", "v")) {
+ # Pull the values of the next cells in the intended direction
+ cur_coords |>
+ get_next_coords(dir) |>
+ mutate(chr = map2_chr(row, col, ~ mtx[.x, .y])) |>
+ anti_join(cur_coords, join_by(row, col)) |>
+ pull(chr) |>
+ unique()
+}
+
+is_blocked <- function(mtx, box_num, dir = c("<", "^", ">", "v")) {
+
+ cur <- get_box_coords(mtx, box_num)
+ nxt_chrs <- get_next_chrs(mtx, cur, dir)
+
+ # Test if the current box is completely blocked or completely free
+ if (any(nxt_chrs == '#'))
+ return(TRUE)
+ else if (all(nxt_chrs == '.'))
+ return(FALSE)
+
+ # Recurse across all later boxes
+ nxt_chrs |>
+ keep(~ str_detect(.x, "^\\d+$")) |>
+ map_lgl(~ is_blocked(mtx, .x, dir)) |>
+ any()
+}
+
+move_box <- function(mtx, box_num, dir = c("<", "^", ">", "v")) {
+ # Get the coordinates of the current box and the place it'll move to
+ cur <- get_box_coords(mtx, box_num)
+ nxt <- get_next_coords(cur, dir)
+
+ # Move all downstream boxes before moving self
+ next_boxes <- get_next_chrs(mtx, cur, dir) |>
+ keep(~ str_detect(.x, "^\\d+$"))
+
+ for (box in next_boxes) {
+ mtx <- move_box(mtx, box, dir)
+ }
+
+ # # Replace the current coords with "." and the next coords with the box
+ mtx[cur$row, cur$col] <- "."
+ mtx[nxt$row, nxt$col] <- box_num
+
+ return(mtx)
+}
+
+```
+
+Loop through puzzle input:
+
+```{r}
+
+run_simulation <- function(mtx, move_seq) {
+ # Convert boxes from format "[]" into ID numbers unique to each box:
+ coords <- list(l = which(mtx == "["), r = which(mtx == "]"))
+ for (i in 1:length(coords$l)) {
+ mtx[coords$l[i]] <- i
+ mtx[coords$r[i]] <- i
+ }
+
+ # Loop through sequence of moves and apply to the map
+ mtx_prv <- mtx
+ for (dir in move_seq) {
+ if (!is_blocked(mtx_prv, box_num = "@", dir = dir)) {
+ mtx_new <- move_box(mtx_prv, box_num = "@", dir = dir)
+ mtx_prv <- mtx_new
+ }
+ }
+
+ return(mtx_new)
+}
+
+output <- run_simulation(mtx, move_seq)
+```
+
+Convert the result to GPS coordinates:
+
+```{r}
+
+output |>
+ as_tibble() |>
+ mutate(row = row_number(), .before = everything()) |>
+ pivot_longer(
+ -row,
+ names_to = "col",
+ names_prefix = "V",
+ names_transform = as.integer
+ ) |>
+ # Select only the leftmost cell of each boxes
+ filter(str_detect(value, "\\d+")) |>
+ slice_min(col, by = value) |>
+ mutate(
+ dist_top = row - 1,
+ dist_left = col - 1,
+ gps = 100 * dist_top + dist_left
+ ) |>
+ pull(gps) |>
+ sum()
+
+```
+
diff --git a/2024/R/day16.qmd b/2024/R/day16.qmd
new file mode 100644
index 0000000..ef5b2ec
--- /dev/null
+++ b/2024/R/day16.qmd
@@ -0,0 +1,169 @@
+---
+title: "Day 16"
+date: 2024-12-16
+author:
+ name: https://adventofcode.com/2024/day/16
+ url: https://adventofcode.com/2024/day/16
+---
+
+## Setup
+
+```{r setup}
+# Libraries
+library(tidyverse)
+library(igraph)
+
+# Read input from file
+input <- read_lines("../input/day16.txt", skip_empty_rows = TRUE)
+```
+
+## Part 1
+
+Convert text input into a weighted, undirected graph
+
+```{r}
+
+# Convert input to a data frame
+df <- input |>
+ str_split("") |>
+ unlist() |>
+ as_tibble_col(column_name = "cell") |>
+ mutate(
+ input_id = row_number() - 1,
+ row = floor(input_id / length(input)),
+ col = floor(input_id %% length(input))
+ )
+
+# Convert borders between grid cells to graph vertices and map edges by cell
+borders <- df |>
+ mutate(border_e = (cell != "#" & lead(cell) != "#"), .by = row) |>
+ mutate(border_s = (cell != "#" & lead(cell) != "#"), .by = col) |>
+ mutate(
+ vtx_id_e = case_when(border_e ~ cumsum(border_e)),
+ vtx_id_s = case_when(border_s ~ cumsum(border_s) + max(vtx_id_e, na.rm = T))
+ ) |>
+ mutate(vtx_id_n = lag(vtx_id_s), .by = col) |>
+ mutate(vtx_id_w = lag(vtx_id_e), .by = row) |>
+ mutate(
+ conn_ns = map2(vtx_id_n, vtx_id_s, ~ na.omit(c(.x, .y))),
+ conn_ew = map2(vtx_id_e, vtx_id_w, ~ na.omit(c(.x, .y))),
+ conn_ne = map2(vtx_id_n, vtx_id_e, ~ na.omit(c(.x, .y))),
+ conn_nw = map2(vtx_id_n, vtx_id_w, ~ na.omit(c(.x, .y))),
+ conn_se = map2(vtx_id_s, vtx_id_e, ~ na.omit(c(.x, .y))),
+ conn_sw = map2(vtx_id_s, vtx_id_w, ~ na.omit(c(.x, .y))),
+ )
+
+# Extract the list of all vertices
+vertices <- c(borders$vtx_id_e, borders$vtx_id_s) |>
+ na.omit() |>
+ sort()
+
+# Convert vertices and edges to an adjacency matrix
+mtx <- borders |>
+ # Unnest lists of edge connections between vertices
+ select(starts_with("conn")) |>
+ pivot_longer(everything(), names_to = "conn", names_prefix = "conn_") |>
+ unnest_wider(value, names_sep = "_") |>
+ drop_na(value_1, value_2) |>
+ # Rotations get an extra 1k added to the weight
+ mutate(weight = case_match(conn, c("ns", "ew") ~ 1, .default = 1001)) |>
+ select(-conn) |>
+ # Convert to matrix format, where unconnected vertices have weight 0
+ complete(value_1 = vertices, value_2 = vertices, fill = list(weight = 0)) |>
+ arrange(value_1, value_2) |>
+ pivot_wider(names_from = value_2, values_from = weight) |>
+ column_to_rownames(var = "value_1") |>
+ as.matrix()
+
+# Make matrix symmetric (for an undirected graph)
+sym_mtx <- pmax(mtx, t(mtx))
+
+# Convert adjacency matrix to a graph
+g <- graph_from_adjacency_matrix(sym_mtx, mode = "undirected", weighted = TRUE)
+
+```
+
+Determine possible starting and ending locations from the input
+
+```{r}
+
+special_cells <- borders |>
+ filter(cell %in% c("S", "E")) |>
+ select(cell, starts_with("vtx_id")) |>
+ pivot_longer(
+ starts_with("vtx_id"),
+ names_prefix = "vtx_id_",
+ names_to = "dir",
+ values_to = "vertex"
+ ) |>
+ drop_na(vertex)
+
+# Create all combinations of start & end cell borders
+combos <- special_cells |>
+ filter(cell == "S") |>
+ mutate(
+ init_rotation = case_match(dir, "e" ~ 0, c("n", "s") ~ 1, "w" ~ 2) * 1000
+ ) |>
+ select(start_vertex = vertex, init_rotation) |>
+ cross_join(
+ special_cells |>
+ filter(cell == "E") |>
+ select(end_vertex = vertex)
+ )
+
+```
+
+Find the minimum path distance for each start/end vertex combo:
+
+```{r}
+
+min_dist <- combos |>
+ mutate(
+ dist = map2_int(
+ start_vertex,
+ end_vertex,
+ ~ distances(g, .x, .y)) + init_rotation + 1
+ ) |>
+ slice_min(dist)
+
+min_dist |>
+ pull(dist)
+
+```
+
+## Part 2
+
+Pull all paths that have the minimum distance from start to end:
+
+```{r}
+
+shortest_paths <- min_dist |>
+ pmap(function(start_vertex, init_rotation, end_vertex, ...) {
+ all_shortest_paths(g, start_vertex, end_vertex)$vpaths
+ }) |>
+ flatten() |>
+ map(as.integer)
+
+
+path_vertices <- shortest_paths |>
+ unlist() |>
+ unique() |>
+ sort()
+
+```
+
+Count all non-wall cells with a border in the shortest path vertex list:
+
+```{r}
+
+borders |>
+ select(cell, input_id, starts_with("vtx_id")) |>
+ pivot_longer(starts_with("vtx_id")) |>
+ drop_na(value) |>
+ filter(map_lgl(value, ~ .x %in% path_vertices)) |>
+ filter(cell != "#") |>
+ distinct(input_id) |>
+ nrow()
+
+```
+
diff --git a/2024/input/day16.txt b/2024/input/day16.txt
new file mode 100644
index 0000000..2002274
--- /dev/null
+++ b/2024/input/day16.txt
@@ -0,0 +1,141 @@
+#############################################################################################################################################
+#.......#.......#...#.....#...............#.....#...........#...............#.....#...#.....#.........#.#...#.....#.........#..............E#
+#.#####.#####.#.#.#.#.###.#.#####.#########.###.#.###.#######.###########.#.###.#.#.#.#.#.#.###.#####.#.#.#.#.#.###.#####.#.#############.#.#
+#...#.#.......#...#...#...#.#.....#...#.....#.#.#.#...#.....#.......#.....#.....#...#.#.#.#...#.#...#...#.#...#.....#...#.#.#.............#.#
+###.#.#################.###.#.#####.#.#.#####.#.#.#.###.###.###.#####.###.###########.###.###.#.###.#.###.#############.#.#.#.#######.#######
+#...................#...#...#.......#...#.....#.#.#...#...#.....#...#.............................#.#.#...#...#.......#.#.#...#.......#.....#
+#.###.#.#########.###.###.#################.#.#.#.#######.#######.#.#.#####.###.#.#.###.#.#.#.#.#.#.#.#.#.#.###.###.#.#.#.#############.###.#
+#.#.#.#.......#...#...#.#.#.........#.....#.#.#.#.....#...#...#...#...#...#.#.#.#.#...#...#.#.#...#.......#.#...#.#.#...#.................#.#
+#.#.#.#######.###.#.###.#.#.#########.#.#.#.#.#.###.#.#.###.#.#.#######.#.#.#.#.###.#.#####.#.#.#########.#.#.###.#.#####################.#.#
+#.#.........#...#.#...#.#.#.#...#.....#.#...#.#...#.#...#.................#...#...#.#.#.....#.#...#.....#.#...#...#...........#...#...#...#.#
+#.#######.#####.#####.#.#.#.#.#.#.#####.#########.#.#####.#######.#.#####.###.###.#.#.#.###.#.#.#.#.###.#.#.#####.#####.#####.#.###.#.###.#.#
+#.#.....#.#...#.........#.#...#.#.#.....#.........#.#...........#...#...#.....#...#.#...#...#.#...#.#.#...#.....#...#...#...#...#...#...#.#.#
+#.#.###.#.#.#.#####.#####.#.#.#.#.#.###.#.#########.#########.#.#######.#####.#.###.#####.#.#.#.#.#.#.#####.###.#.#.#.###.#.#.###.#####.###.#
+#.....#.#.#.#.....#...#...#.#...#.#...#.#.#.....#...#...#.....#.........#.....#...#.#.....#.#.................#...#.#.....#.#.#...#...#.....#
+#.#####.#.#.#####.#####.###.#.###.###.###.#.#.###.###.#.#.###.#########.#####.###.#.#.#########.#.#.#######.#.#####.#######.###.###.#######.#
+#.#...#.#.#.#...#.........#.#...#...#.#.....#.....#...#.#.#.......#.....#.....#.#.#.#...#.........#.....#.......#.........#.#...#...#.......#
+#.#.#.#.#.#.#.###########.#.###.###.#.#.#######.###.###.#.#.#.###.#.#####.###.#.#.#####.#.#######.#####.#.#####.#.#########.#.###.#.#.#######
+#.#.#...#.#.#.#.........#...#.#.....#.#.......#.....#.....#.#.....#...#.....#...#.#.....#...#.#.........#.#.....#.#.........#.#...#.#.....#.#
+#.#.#.#####.#.#.###.###.#.###.#######.###.###.###############.#.#####.###.#.#.###.#.###.###.#.#.#########.#.#.#.###.#########.#.###.#####.#.#
+#.#.#.#.....#...#...#...#.#.........#.......#.....#...#.....#.......#...#...#.#...#.#.....#.#.#...#...#...#.#.#...#.....#.....#...#.....#.#.#
+#.#.###.###.###.#.#######.#.###.###.#####.#.#####.#.#.#.###.#.#####.###.#.###.#.###.#####.#.#.###.#.#.#.#####.###.#####.#.#######.###.#.#.#.#
+#.#...#.......#...#.......#...#...#.#.....#...#.#...#.#...#.#...#.....#.#.....#...#...#...#.....#...#...#...#...#.....#.#.#...#...#...#.#.#.#
+#.###.#####.#.#.###.#########.###.###.#######.#.#####.###.#.#####.###.#.#.#.#####.#.#.#########.#########.#.#.#.#####.#.#.#.#.###.#.#####.#.#
+#.#.....#...........#.......#...#...#.....#...#.......#...#.....#.....#...#.....#.#.#.#.......#.#.........#...#...#...#...#.#...#.#.....#...#
+#.#.#####.#.###.#.###.#####.#####.#.###.#.#.#######.#.#.#######.###.#####.###.#.#.#.#.#.#.#####.#.#.###############.###.#.#.###.#.###.#.###.#
+#...............#.#.#.....#.....#.......#.#...#...#.#...#...#...#...#.........#.#.#.#.#.#.......#.#.#...#.........#.....#.#...#.#.....#.....#
+#.#########.###.#.#.#.###.#####.#.#.#.#.#.###.#.#.#.#####.###.###.###.#####.#####.###.#.#####.#.###.#.#.#.#######.#####.#.#.###.###.#.###.###
+#.....#...#.#.#...#.....#.....#.#.#.#.#.#...#...#.........#...#.......#...#.#...#...#.#.#.....#.....#.#...#...#.......#.#...#...........#...#
+#####.#.#.#.#.#####.#####.#.###.#.#.#.#.###.#.#####.###.###.###.#######.#.###.#.#.#.#.#.#.###.#####.#.#######.#.#####.#.#####.###.###.#.#####
+#...#.#.#.#...#.#...#.....#...#...#...#...#.#.#.......#.#...#...#...#...#.#...#.#.#.#...#...#...#...#.#.......#...#...#.....................#
+#.#.#.#.#.###.#.#.###.#####.#.###########.#.###.#####.#.#.###.###.###.###.#.###.###.#######.#####.###.#####.#####.###.#.#.#.###.###.#.#####.#
+#.#...#.#.....#.....#.#.....#.......#...#.........#...#.#.#...#.#...#...#...#.#...#.#.....#...#...#.#.....#...#...#.....#.#...#.#...#.....#.#
+#.#####.#############.#####.###.###.###.#.###.#####.#####.#.###.#.#.###.###.#.#.#.#.#.###.#.#.#.###.#####.#.#.#.#.#.#####.###.#.#.###.###.#.#
+#.#...#.......#.....#.....#.#...#.#.#...#...#.......#.....#.#.....#...#.#.......#.#.#.#.#.#.#.#.#...#.....#.#.#.#.#.#.......#.....#.......#.#
+#.###.#######.#.###.#.###.#.#.###.#.#.#.#.###.###.###.#####.#.#######.#.#.#####.#.#.#.#.#.###.#.#.#.#.###.#.#.#.###.#######.#.#####.#.#####.#
+#.#...#.....#...#.#.#...#...#.#.......#.#.#...#...#...#.#.....#.....#.#...#...#...#.....#.#...#...#...#...#.#.#...#.....#...#...#...#.#.....#
+#.#.###.#.#######.#.#####.###.#####.#####.#.#####.#.###.#.###.#.###.#.#####.###.#.#####.#.#.#####.#####.#####.###.#.###.#.###.#.###.#.#.###.#
+#.#.....#.#.......#...#...#...#...#.#.....#.....#.#...#.#...#.#.#.#...#...#.....#.....#.#.#.......#.........#.#...#.....#...#.........#...#.#
+#.#.#####.#.###.#####.#.###.###.#.###.#########.#.###.#.###.###.#.###.#.#.#.#########.###.#########.#######.#.#.###.#####.###.###.#.#.#.#.###
+#.#.#...#.#.#.......#.#.#.......#...#.........#.#.#...#.....#...#.....#.#.#.#.....#.#...#...#.........#...#...#.#...#.....#...#.#...#...#...#
+#.#.#.#.#.#.#.#####.#.#.#######.###.#.#######.#.#.#.###.#####.#######.#.#.#.#.###.#.###.###.#.#########.#.#####.#.###.#####.###.###.###.###.#
+#.#.....#.........#.#.#...#...#...#...#.....#.#.#.#.#.........#.....#...#.#...#...#...#.#...#.#.....#...#.#...#...#.#.#.#...#...........#.#.#
+#.###.###########.#.#.###.#.#.###.#####.###.#.#.#.#.###########.###.###.#######.###.###.#.###.###.#.#.#.#.#.#.#.###.#.#.#.###.###.#.#.#.#.#.#
+#.........#.......#.....#...#.#.#.....#.#...#.#.#.#.......#...#...#.......#.....#...#...#.........#.#.#.#.#.#.#.#.....#.#.#...........#.....#
+#####.###.#.###########.#####.#.#.#####.#.#####.#.#####.#.#.#.#.#####.###.#.#####.#.#.###.#########.#.#.#.#.#.#.#####.#.#.###.#####.###.#.#.#
+#.......#.#.......#...#.......#...#.....#.....#.#.#...#.#.#.#...#...#...#...#.....#.#...#.....#.....#.#.#...#.#.....#...#...#...#...#.....#.#
+#.###.###.#########.#.#########.###.#####.###.#.###.#.#.#.#.#####.#.###.#.###.###.#####.#######.#.###.#.#####.#####.#######.#.###.#.###.#.#.#
+#...#...#.#.........#.#.......#.#...#...#.....#...#.#...#...#.#...#.#...#.....#...#.....#.......#.#.....#.....#...#.........#.#...#.........#
+###.#.#.#.#.#########.#.###.#.#.#.###.###.#######.#.###.#.###.#.###.#.#.#######.###.#####.#####.#.#.#####.#######.###########.#.#######.#.#.#
+#...................#.#...#.#.#.#.#.......#.......#.#.#.#.#...#.#.#...#.#...#.#...#.......#...#.#...#.....#.....#.........#...#...#.....#...#
+#.###.#.#####.#####.#.###.#.#.#.#.#####.#####.###.#.#.#.#.###.#.#.#.#.#.#.#.#.###.###.#####.#.#######.###.#.###.#########.#.#####.#.###.#.###
+#.....#...#.#...#...#.#...#.#.#.#.....#.....#.#...#.#...#...#.#.#.#.#.#...#.#...#.#.#.......#...#.....#...#...#.........#.#.......#.#...#.#.#
+#.###.#.#.#.#.#.#####.#.###.###.#####.#####.#.#####.#.#####.#.#.#.#.#.#####.#.###.#.#.#########.#.###########.#########.#.#.###.###.#.#.#.#.#
+#...#...#...#.#...#...#...#.....#.#...#.......#.....#.#.#...#.#.......#.#...#...#.#.#.#.......#...#...........#.........#.#.#...#...#.......#
+###.#.#####.#.###.#.#####.#######.#.###.#.###.#.#####.#.#.###.#.#######.#.###.#.#.#.#.#.#####.###.#.#.#########.#########.#.#.###.#####.#.#.#
+#.#.#.#...#.#.#.#...#...#.#.......#...#.#.#.#.#...#...#.....#.#.....#.....#...#...#.#...#...#.#...#.....#.....#.....#...#...#.......#.....#.#
+#.#.#.###.#.#.#.#####.###.#.#.#####.#.#.#.#.#.###.#.###.###.#.#####.###.#######.###.#####.#.#.#.#.#####.###.#######.#.###.#.#####.#.#.#.#.#.#
+#...#...#.#.......#.......#...#...#.#...#.#.....#.#...#...#.......#...#...#...#.....#...#.....#.#...#.......#.......#.#...#.....#.#...#.....#
+#.#####.#.#.#####.#######.#.###.#.#######.#######.###.#.#########.###.###.#.#.#.#####.#.#.#####.###.#.#######.#######.#.###.###.#######.#.###
+#.#.....#.#.#...#.......#.#...#.#.......#.#.....#.#...#.#.........#.#.#.#...#.#.....#.#.#.....#...#.#...#.............#...#...#.....#...#...#
+#.#.#####.#.#.#########.#.###.#.#######.#.#.###.#.#.###.#.#####.###.#.#.#.###.#.###.#.#.###.#.#.###.###.#.#####.#########.###.#####.#.###.#.#
+#.#.#...#.#.#.....#.....#...#.#...#.......#...#...#...#...#...#.....#.......#...#.#...#...#.#.#.......#.#.....#.........#...#...#...#.#...#.#
+#.#.#.#.#.#.###.#.#.#######.#.###.#.#########.#.#####.#####.#.#####.#.###.#######.###.###.#.#.#########.#####.#.#######.###.###.#.#.#.#.###.#
+#.#.#.#...#.#...#.#.#.......#...#.#.#.......#.#.#.....#.....#.....#...#...#.....#.......#.#.#...........#...#.#...#...#.......#.#.#...#.#...#
+###.#.#.###.#.#####.#.#########.#.###.#####.#.#.#.#####.#######.#.###.#.#.#.###.#.#####.#.#.#############.#.#.###.###.###.###.#.#.#.###.#.#.#
+#...#.......#...#...#.....#.....#.....#...#.#.#.........#...#...#...#.#.#.#...#.#.....#.............#.....#...#.........#.....#...#.....#.#.#
+#.###.#########.#.#.#####.###.#.#######.#.#.#.###########.###.#.###.#.#.#####.#.#####.#####.#########.#######################.#.#.#.#####.#.#
+#.#...........#.#.#...#.#...#.#.........#...#.......#.....#...#.......#.....#.#.....#.#.....#...#.....#...#.......#.....#...#.#.#.#.....#.#.#
+#.###########.#.#.#.#.#.###.#.#########.###.#######.#####.#.#############.###.#####.#.#######.#.#.###.#.###.###.#.#.###.#.#.###.#.#######.###
+#...........#.#.#...#.#.....#.......#...#.....#...#.#...#...........#...#...#...............#.#.#...#.#.....#...#...#...#.#.....#.......#...#
+#####.#.#####.#.#####.#.#####.#####.#.###.###.#.#.#.#.#.#####.#######.#.###.###.#.###.#.###.#.#.###.#.#.#####.#######.###.#############.###.#
+#.....#.#...#.#.....#.#...#.......#.#.#...#...#.#.#...#...#.....#.....#.#.....#.......#.#...#.#.#...#.#.#...#...#.....#...#...#.....#.#...#.#
+#.#####.#.#.#.#.###.#.###.#.#####.#.#.#.###.###.#.#######.#.###.#.#######.#####.#.#####.#.###.#.#.###.#.#.#####.#.#####.###.#.#.###.#.###.#.#
+#...#...#.#...#...#.#...#...#...#.#.#.#...#...#.#.....#...#.#.#...............#.......#.#.#...#.#.#...#.#.....#.#.......#...#...#.......#.#.#
+###.#.#.#.#######.#####.#.###.#.###.#####.###.#.###.#.#.#.#.#.#.###.#########.#######.#.#.#.###.#.#.#.#.#####.#.#########.#######.#######.#.#
+#...#.#...........#.....#...#.#.....#.....#.#.#.#...#.#.#.#.#.......#.......#.......#...#.#...#...#.#...#.....#.....#...........#...#.....#.#
+#.###.#########.###.#######.#.#.#.###.#####.#.###.#####.###.#######.#.#####.#.#####.#####.#.#.#########.#.#######.#.#.#########.###.#.#####.#
+#...#...........#...#.....#...#.#.#...#...#.......#...#.#...#.....#.#...#.#.#.....#...#.#.#.#.#.......#...#.....#.#.#...#.....#.#...#.#.....#
+#.#.#########.###.###.#########.#.#.#.#.#.#######.#.#.#.#.###.###.#.###.#.#.#####.#.#.#.#.###.#.###.#.#.###.###.#.#.###.###.#.#.###.#.#.###.#
+#.#.........#.#...#...............#...#.#.....#...#.#...#.....#.#.#...#.#...#...#.#.#...#.....#...#.#.......#...#.#.......#.................#
+#.#########.###.#########.#.#########.#.#####.#####.###.#######.#.#####.#.###.#.###.#.#.###########.#########.#####.#.###.#.#####.###.###.#.#
+#...#.....#...#.#.......#...#.....#...#.....#.....#.#...........#.#.....#.....#.....#.............#.....#...#.#...#.#...#.#.#...#...#.#...#.#
+###.#.###.###.#.#.#.###.#.###.###.#.#######.#####.#.###.#######.#.#.#############################.#####.#.#.#.#.#.#####.#.#.#.#.###.#.#.#.#.#
+#.#...#...........#.#...#.#.#.#...#.........#.#...#.....#.........#.#...#.....#...#...#.........#.......#.#.#...#.#.....#.#...#.#...#...#.#.#
+#.#####.###.#.#####.#.###.#.#.#.#########.#.#.#.#.#####.#.#########.#.###.#.#.###.#.#.#.#.#.#############.#.#####.#.#####.#####.#.#######.#.#
+#.......#...#.........#.....#...........#.....#.#.....#.#...#.....#.#.....#.#...#...#.#.#.#.#.....#.....#.#.#...#.#...#...#.....#.........#.#
+#.#####.#.#.#############.#.#.#########.#####.#.#####.#.###.#.#.#.#.#######.###.#.###.#.#.###.#.#.#.#.#.#.#.###.#.###.#.###.###.#####.#####.#
+#...#...#.#.............#...#.....#.....#.....#.#.....#.....#.#.#...#.......#...#.#...#.#...#.#.#.#.#.....#.....#.....#.#...#.#...#...#...#.#
+###.#.#.#.###########.#.#########.#.#######.###.#######.#####.#.#####.#######.#.#.#.###.###.#.#.#.#.#.#################.#.###.###.#.###.#.#.#
+#.....................#...#.....#.#.......#...#.......#.....#.#.#.....#.....#.#...#.#...#...#.#.#.#.#.#...............#.#.#.#...#.#.....#.#.#
+#.###.#.#.###.###########.#.###.#.#######.#####.#####.#.#.#.###.#####.#.#####.#.###.#.###.###.#.###.#.#.#########.#####.#.#.#.#.#.#######.#.#
+#...#...#.#...#.........#...#...#.......#.....#.....#...#.#...#.....#.#...#...#.#...#.#.#.....#.....#...#.......#.....#.......#.#...#.#...#.#
+###.###.#.#.###.#######.#####.#########.#####.#######.#.#.###.#####.#.#.#.#.#####.###.#.#############.#####.#.#.#####.#####.###.###.#.#.###.#
+#.#...#...#.#...#.....#.#...............#...#.....#...#.#.#.#.......#.#...#.#...#...#.....#.......#.......#.#.#.........#...#.#...#.#.#.#...#
+#.###.#.###.#.#######.#.#.#.#############.#.#.###.#.#.#.#.#.#########.#.###.#.#.###.#####.#####.#.#####.#.###.#####.###.#.###.#.###.#.#.#.###
+#.....#...............#.#.#.....#.....#...#.....#...#...#.#...........#.......#.......#...#.....#.......#.....#...#.#.#...#...#...#.#.#...#.#
+#.#############.#####.#.###.#.###.#.###.#.#####.#####.###.#.#.#########.###############.###.###################.#.#.#.#######.###.#.#.#####.#
+#.#.......#...#.#.....#...#.#.....#.#...#.#...#.....#.#...#.#.#.............#...........#.#...#...#.........#...#.#.#...#.......#.#.#.......#
+#.###.###.#.#.#.#.#.###.#.###.#####.#.###.###.#.###.#.#.#.#.###.#.#.#########.#######.###.#.#.###.#.#####.#.#.###.#.#.#.###.###.#.#.#.#####.#
+#.....#...#.#.#.#.#...#.#...#.....#...#...#.......#.#.#.#.#.....#.#...........#.#...#.......#.........#.#.#...#...#...#.....#...#.#...#.#...#
+#######.###.#.###.###.#####.#.###.#####.###.#######.#.#.#.#.#.###.#.###########.#.#.#.###.#.###.#####.#.#.#####.#############.###.#####.#.###
+#.....#.#...#.#...#.........#...#.....#...#.........#.#.#...#.......#.....#...#.#.#.#.#...#...#...#.#.#.#.#...#...#.....#...#...#.......#...#
+#.#.###.#.###.#.#######.#.#####.#.###.###.###########.#.#.#######.#.#.###.#.#.#.#.#.#.#.#####.###.#.#.#.#.#.#.#.#.#####.#.#.###.#####.#####.#
+#.#...#...#...#...#...#.#.....#.....#...#.#...........#.#.....#...#.#.#.#...#.#...#.#.#.#.......#.#.#.#.#...#.#.#.#.....#.#.....#...#.......#
+#####.#####.###.#.#.#.#.###.#.#.###.#.#.#.#.###########.#####.#.###.#.#.#####.###.#.#.#.#.#######.#.#.#.#####.#.#.#.###.#.#######.#.#######.#
+#.........#.#.#.#...#.#...#.#.#...#.#.#.#.#.#...........#.....#...#...#.....#...#.#...#.......#...#.#.#.....#.#.....#...#.#.................#
+#.#####.###.#.#.#####.###.#.#.###.###.###.#.#.#.#########.#.#.###.#####.###.###.###.#########.#.###.#.#.###.#.#.#.#######.#####.#####.###.#.#
+#.......#...#.#.....#.#...#.#.#.......#...#.#.#.#.......#.#.#.#...#.#...#.....#...#.#...#.....#...#.#...#...#.#.#.......#.#...#.#...#...#.#.#
+#.#####.#.###.#####.#.#.#####.#.#####.#.###.###.#.#####.#.#.#.#.###.#.#.#.###.###.###.#.#########.#.#.#.#.#.#.###.#####.#.#.#.#.#.#.###.###.#
+#.#...#.#.#.......#.#.#.......#.......#.#...#...#.....#...#.#.#.#.......#.#.#...#...#.#...#.......#...#...#.#.....#.......#.#...#.#.......#.#
+#.#.#.###.#.#######.#.#########.#######.#.###.###.###.#######.#.#.#####.#.#.###.###.#.###.#.#######.###.#.#########.#.#####.#############.#.#
+#...#...#.#.........#.#...........#.#...#.....#.#...#.......#...#.....#...#...#...#.#...#...#.....#...#.#.....#...#.#.....#...........#...#.#
+#.#####.#.#########.#.#####.#####.#.#.#########.###.#######.#########.#####.#.#.###.#.#.#####.#.#.###.#.###.#.#.#.#####.###.#########.#.###.#
+#.#...#.#.#.......#.#.#.....#...#.#.#.......#.....#.#.....#...#...#...#.....#.#.#...#.#.#.....#.....#.#...#.#...#.#...#.#...#.........#...#.#
+#.###.#.#.#.#.###.###.#.###.#.#.#.#.###.###.###.###.#.###.#.###.#.#.#####.#####.#.#####.#.#####.#####.#####.#####.#.#.#.#.###.###########.#.#
+#.....#.#...#...#.....#.#...#.#.......#.#.#.....#...#.#...#...#.#.#.#.....#...#...#...#.#.#.#...#...#.....#.........#...#.#.#...............#
+#####.#.#####.#########.#####.#########.#.#.#####.###.#######.#.#.#.#.###.#.#.#####.#.#.#.#.#.###.#.#####.#####.#######.#.#.#.#.#.#.###.#.#.#
+#...#.#...............#.........#.......#...#.....#...#.....#...#.#.#...#.#.#.......#.#.#.#.#.....#.......#.....#...#...#...#...#.#.#...#.#.#
+#.###.#.#.#.#.#.#####.#.#########.#######.###.#####.###.#.#####.#.#.#.#.###.###.#####.#.#.#.###.#####.#.#.#.###.#.#.#.#####.#####.#.#####.#.#
+#.#...#.#.#...#.#...#.#...#.#.....#.......#.#.#...#...#.#...#.....#.#.#.......#.#.#...#.#...#.......#.#.#.#.#.#.#.#.#.#.....#.....#...#.....#
+#.#.#.#.#.###.#.#.#.#####.#.#.###########.#.#.#.#.###.#.###.#.#.###.#.#########.#.#.###.###.#####.###.###.#.#.#.#.#.###.#####.#######.#.###.#
+#.#...#...#...#.#.#.#.....#.#...#.......#...#...#...#...#...........#.#.........#.......#.#.#...#...#.....#.#...#.#.#...#.....#...#...#...#.#
+#.###.#####.#.#.#.#.#.#####.###.#.#####.###########.#####.#############.#######.#########.#.#.#.###.#######.#####.#.#.###.#####.#.#.#####.#.#
+#.#...#.....#.#.....#.........#.....#...#.........#.....#.#.....#.....#.......#.#...#.....#...#.......#...........#.....#...#...#.#.....#...#
+#.#.#.#.#####.#.###.###.#############.###.###.#####.###.#.#.###.#.#.#.#.#.###.###.#.###.#.###########.#.#########.#########.#.###.###.#.###.#
+#.#...#...........#.....#...#.......#...#.#.#.......#...#.....#...#.#...#...#...#.#...#...........#...#.#...#...#.#.......#...#...#...#.#...#
+#.###.#.###.#.###########.#.#.#.###.###.#.#.#####.###.###.#########.###.#####.#.#.#.#.###.#######.#.#####.#.#.#.###.#####.#.###.###.#.###.###
+#.#...#...#...#.....#...................#.......#...#.#...............#.#...#.#...#.#...#.....................#.....#.....#...#...#.#.#...#.#
+#.#.#.###.#.#.#.###.#.###.#####.#.###.###.#######.#.#.#####.#########.#.#.#.#.#####.###.#.#.###.#####.#####.#########.#######.###.#.#.#.###.#
+#.#.#...............#...#.#...#...#.......#.....#.#.#.....#.................#.........#.#.......#.......#.......#...#...#.....#...#.#.#.#...#
+#.#.#.#######.#.#.#####.###.#.###.###.#####.###.###.#####.#.#.#####.###.#.#.###########.#.#.###.#######.#.#.#####.#.###.###.###.###.#.#.#.###
+#...#...#.#.....#.....#.#...#...#...#...#...#...........#.#.#.#...#.#.........................#.........#.#.......#...#...#...#...#.#.#.#...#
+#.#.###.#.#.#########.#.#.#####.###.#####.###.###########.###.#.#.#.#.###.#.#.###.#.#.#.#.#.#.###########.#.#####.#.#.#.#.#######.#.###.#.#.#
+#.#...#.#...#.......#.#.#.....#...#.......#.....#.......#...#...#.#.#.#...#.#.#.#...#.#.#.#.#.................................#.....#...#.#.#
+#.#.#.#.#####.#####.#.#.#.#####.#.###############.#####.###.#####.#.#.#.###.#.#.#####.#.#.#.#####.#.#.#.###.#.#.###.###.#####.#.###.#.#####.#
+#.#...#.....#.#.....#...#.#.......#.....#.............#...#.....#.#.#.#.#.#.....................#.#...#...#...#...#...#.#...#...#...#.....#.#
+#.#.#.#####.#.#.###.###.#.#.###.#.#.###.#.#############.#######.#.#.#.#.#.#.#.###.#######.#.#.#.#.#######.#.#####.#.#.#.###.#####.#.#####.#.#
+#...#...#...#.#...................#...#.#...#...........#.......#.#...#.#.#.#...#.#.......#.....#...#...#...#.....#.#.#.....#.....#.....#.#.#
+###.###.#.###.#.#.#######.#.###.#####.#.###.#.###########.#######.#.###.#.#.###.#.###.###.#.###.#####.#.#####.#####.#.#######.#.#########.#.#
+#S......#.......#.........#...........#.....#.....................#.....#.......#.....#.....#.........#.......#.....#.........#.............#
+#############################################################################################################################################
diff --git a/_freeze/2024/R/day15/execute-results/html.json b/_freeze/2024/R/day15/execute-results/html.json
index c93c0f6..899a762 100644
--- a/_freeze/2024/R/day15/execute-results/html.json
+++ b/_freeze/2024/R/day15/execute-results/html.json
@@ -1,8 +1,8 @@
{
- "hash": "da65cd066eedd1b1b4f857511ed7322e",
+ "hash": "c578aa95e3f71784a13de4cf642cfcbc",
"result": {
"engine": "knitr",
- "markdown": "---\ntitle: \"Day 15\"\ndate: 2024-12-15\nauthor:\n name: https://adventofcode.com/2024/day/15\n url: https://adventofcode.com/2024/day/15\n---\n\n\n\n\n## Setup\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Libraries\nlibrary(tidyverse)\n\n# Read input from file\ninput <- read_lines(\"../input/day15.txt\")\ninput_wh <- keep(input, ~ str_detect(.x, \"#\"))\ninput_mv <- keep(input, ~ str_detect(.x, \"<|>|\\\\^|v\"))\n```\n:::\n\n\n\n\n## Part 1\n\n\n\n\n\n\n\n\n\nConvert warehouse input to a row/column indexed dataframe\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert WH input text to a matrix\nmtx <- input_wh |>\n str_split(\"\") |> \n matrix() |> \n unlist() |> \n matrix(byrow = TRUE, nrow = length(input_wh))\n\n\n# Convert movement sequence to a seq of characters\nmove_seq <- input_mv |> \n str_c(collapse = \"\") |> \n str_split_1(\"\")\n```\n:::\n\n\n\n\nDefine function to update the map based on a single movement of the robot::\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmove_robot <- function(mtx, dir) {\n # Get the current coordinates of the robot\n robot <- which(mtx == \"@\", arr.ind = TRUE)\n row <- robot[1, \"row\"]\n col <- robot[1, \"col\"]\n \n # Define the range of matrix values to adjust according to the movement dir\n row_end <- case_match(dir, c(\"<\", \">\") ~ row, \"^\" ~ 1, \"v\" ~ nrow(mtx))\n col_end <- case_match(dir, c(\"^\", \"v\") ~ col, \"<\" ~ 1, \">\" ~ nrow(mtx))\n \n # Using obstacle logic, determine the set of new characters\n new <- tibble(\n orig = mtx[row:row_end, col:col_end],\n lag = lag(orig)\n ) |> \n mutate(\n is_empty = orig == \".\",\n is_wall = orig == \"#\",\n is_blocked = accumulate(is_wall, `|`),\n is_fillable = is_empty & !is_blocked,\n first_fillable = is_fillable & !lag(accumulate(is_fillable, `|`)),\n can_move = accumulate(first_fillable, `|`, .dir = \"backward\"),\n new = if_else(can_move, coalesce(lag, \".\"), orig)\n ) |> \n pull(new)\n \n # Replace the affected characters in the matrix and return\n mtx[row:row_end, col:col_end] <- new\n return(mtx)\n}\n```\n:::\n\n\n\n\nDefine a function to iteratively run the set of movements\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nrun_simulation <- function(mtx, move_seq) {\n mtx_prv <- mtx\n for (dir in move_seq) {\n mtx_new <- move_robot(mtx_prv, dir)\n mtx_prv <- mtx_new\n }\n return(mtx_new)\n}\n```\n:::\n\n\n\n\nDefine a function to determine the GPS coordinates of all boxes\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nget_boxes_gps <- function(mtx) {\n which(mtx == \"O\", arr.ind = TRUE) |> \n as_tibble() |> \n mutate(\n gps = 100 * (row - 1) + (col - 1)\n ) |> \n pull(gps)\n}\n```\n:::\n\n\n\n\nRun puzzle input:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmtx |> \n run_simulation(move_seq) |> \n get_boxes_gps() |>\n sum()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 1457740\n```\n\n\n:::\n:::\n",
+ "markdown": "---\ntitle: \"Day 15\"\ndate: 2024-12-15\nauthor:\n name: https://adventofcode.com/2024/day/15\n url: https://adventofcode.com/2024/day/15\n---\n\n\n\n\n## Setup\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Libraries\nlibrary(tidyverse)\n\n# Read input from file\ninput <- read_lines(\"../input/day15.txt\")\ninput_wh <- keep(input, ~ str_detect(.x, \"#\"))\ninput_mv <- keep(input, ~ str_detect(.x, \"<|>|\\\\^|v\"))\n```\n:::\n\n\n\n\n## Part 1\n\n\n\n\n\n\n\n\n\nConvert warehouse input to a row/column indexed dataframe\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert WH input text to a matrix\nmtx <- input_wh |>\n str_split(\"\") |> \n matrix() |> \n unlist() |> \n matrix(byrow = TRUE, nrow = length(input_wh))\n\n\n# Convert movement sequence to a seq of characters\nmove_seq <- input_mv |> \n str_c(collapse = \"\") |> \n str_split_1(\"\")\n```\n:::\n\n\n\n\nDefine function to update the map based on a single movement of the robot::\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmove_robot <- function(mtx, dir) {\n # Get the current coordinates of the robot\n robot <- which(mtx == \"@\", arr.ind = TRUE)\n row <- robot[1, \"row\"]\n col <- robot[1, \"col\"]\n \n # Define the range of matrix values to adjust according to the movement dir\n row_end <- case_match(dir, c(\"<\", \">\") ~ row, \"^\" ~ 1, \"v\" ~ nrow(mtx))\n col_end <- case_match(dir, c(\"^\", \"v\") ~ col, \"<\" ~ 1, \">\" ~ nrow(mtx))\n \n # Using obstacle logic, determine the set of new characters\n new <- tibble(\n orig = mtx[row:row_end, col:col_end],\n lag = lag(orig)\n ) |> \n mutate(\n is_empty = orig == \".\",\n is_wall = orig == \"#\",\n is_blocked = accumulate(is_wall, `|`),\n is_fillable = is_empty & !is_blocked,\n first_fillable = is_fillable & !lag(accumulate(is_fillable, `|`)),\n can_move = accumulate(first_fillable, `|`, .dir = \"backward\"),\n new = if_else(can_move, coalesce(lag, \".\"), orig)\n ) |> \n pull(new)\n \n # Replace the affected characters in the matrix and return\n mtx[row:row_end, col:col_end] <- new\n return(mtx)\n}\n```\n:::\n\n\n\n\nDefine a function to iteratively run the set of movements\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nrun_simulation <- function(mtx, move_seq) {\n mtx_prv <- mtx\n for (dir in move_seq) {\n mtx_new <- move_robot(mtx_prv, dir)\n mtx_prv <- mtx_new\n }\n return(mtx_new)\n}\n```\n:::\n\n\n\n\nDefine a function to determine the GPS coordinates of all boxes\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nget_boxes_gps <- function(mtx) {\n which(mtx == \"O\", arr.ind = TRUE) |> \n as_tibble() |> \n mutate(\n gps = 100 * (row - 1) + (col - 1)\n ) |> \n pull(gps)\n}\n```\n:::\n\n\n\n\nRun puzzle input:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmtx |> \n run_simulation(move_seq) |> \n get_boxes_gps() |>\n sum()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 1457740\n```\n\n\n:::\n:::\n\n\n\n\n## Part 2\n\nWiden the map:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert WH input text to a matrix\nmtx <- input_wh |> \n str_replace_all(\"#\", \"##\") |> \n str_replace_all(\"O\", \"[]\") |> \n str_replace_all(\"\\\\.\", \"..\") |> \n str_replace_all(\"@\", \"@.\") |>\n str_split(\"\") |> \n matrix() |> \n unlist() |> \n matrix(byrow = TRUE, nrow = length(input_wh))\n```\n:::\n\n\n\n\nDefine functions to move boxes around the map:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nget_box_coords <- function(mtx, box_num) {\n as_tibble(which(mtx == box_num, arr.ind = TRUE))\n}\n\nget_next_coords <- function(cur_coords, dir = c(\"<\", \"^\", \">\", \"v\")) {\n cur_coords |>\n mutate(\n row = row + case_match(dir, \"^\" ~ -1, \"v\" ~ 1, .default = 0),\n col = col + case_match(dir, \"<\" ~ -1, \">\" ~ 1, .default = 0),\n )\n}\n\nget_next_chrs <- function(mtx, cur_coords, dir = c(\"<\", \"^\", \">\", \"v\")) {\n # Pull the values of the next cells in the intended direction\n cur_coords |>\n get_next_coords(dir) |> \n mutate(chr = map2_chr(row, col, ~ mtx[.x, .y])) |> \n anti_join(cur_coords, join_by(row, col)) |> \n pull(chr) |> \n unique()\n}\n\nis_blocked <- function(mtx, box_num, dir = c(\"<\", \"^\", \">\", \"v\")) {\n \n cur <- get_box_coords(mtx, box_num)\n nxt_chrs <- get_next_chrs(mtx, cur, dir)\n \n # Test if the current box is completely blocked or completely free\n if (any(nxt_chrs == '#')) \n return(TRUE)\n else if (all(nxt_chrs == '.')) \n return(FALSE)\n \n # Recurse across all later boxes \n nxt_chrs |> \n keep(~ str_detect(.x, \"^\\\\d+$\")) |> \n map_lgl(~ is_blocked(mtx, .x, dir)) |> \n any()\n}\n\nmove_box <- function(mtx, box_num, dir = c(\"<\", \"^\", \">\", \"v\")) {\n # Get the coordinates of the current box and the place it'll move to\n cur <- get_box_coords(mtx, box_num)\n nxt <- get_next_coords(cur, dir)\n \n # Move all downstream boxes before moving self\n next_boxes <- get_next_chrs(mtx, cur, dir) |> \n keep(~ str_detect(.x, \"^\\\\d+$\"))\n \n for (box in next_boxes) {\n mtx <- move_box(mtx, box, dir)\n }\n \n # # Replace the current coords with \".\" and the next coords with the box\n mtx[cur$row, cur$col] <- \".\"\n mtx[nxt$row, nxt$col] <- box_num\n \n return(mtx)\n}\n```\n:::\n\n\n\n\nLoop through puzzle input:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nrun_simulation <- function(mtx, move_seq) {\n # Convert boxes from format \"[]\" into ID numbers unique to each box:\n coords <- list(l = which(mtx == \"[\"), r = which(mtx == \"]\"))\n for (i in 1:length(coords$l)) {\n mtx[coords$l[i]] <- i\n mtx[coords$r[i]] <- i\n }\n\n # Loop through sequence of moves and apply to the map\n mtx_prv <- mtx\n for (dir in move_seq) {\n if (!is_blocked(mtx_prv, box_num = \"@\", dir = dir)) {\n mtx_new <- move_box(mtx_prv, box_num = \"@\", dir = dir)\n mtx_prv <- mtx_new\n } \n }\n \n return(mtx_new)\n}\n\noutput <- run_simulation(mtx, move_seq)\n```\n:::\n\n\n\n\nConvert the result to GPS coordinates:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\noutput |> \n as_tibble() |> \n mutate(row = row_number(), .before = everything()) |> \n pivot_longer(\n -row, \n names_to = \"col\", \n names_prefix = \"V\", \n names_transform = as.integer\n ) |> \n # Select only the leftmost cell of each boxes\n filter(str_detect(value, \"\\\\d+\")) |> \n slice_min(col, by = value) |> \n mutate(\n dist_top = row - 1,\n dist_left = col - 1,\n gps = 100 * dist_top + dist_left\n ) |> \n pull(gps) |> \n sum()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 1467145\n```\n\n\n:::\n:::\n",
"supporting": [],
"filters": [
"rmarkdown/pagebreak.lua"
diff --git a/_freeze/2024/R/day16/execute-results/html.json b/_freeze/2024/R/day16/execute-results/html.json
new file mode 100644
index 0000000..c143987
--- /dev/null
+++ b/_freeze/2024/R/day16/execute-results/html.json
@@ -0,0 +1,15 @@
+{
+ "hash": "e84728141f6bbc818304b0649be3cfb4",
+ "result": {
+ "engine": "knitr",
+ "markdown": "---\ntitle: \"Day 16\"\ndate: 2024-12-16\nauthor:\n name: https://adventofcode.com/2024/day/16\n url: https://adventofcode.com/2024/day/16\n---\n\n\n\n\n## Setup\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Libraries\nlibrary(tidyverse)\nlibrary(igraph)\n\n# Read input from file\ninput <- read_lines(\"../input/day16.txt\", skip_empty_rows = TRUE)\n```\n:::\n\n\n\n\n## Part 1\n\nConvert text input into a weighted, undirected graph\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# Convert input to a data frame\ndf <- input |> \n str_split(\"\") |> \n unlist() |> \n as_tibble_col(column_name = \"cell\") |> \n mutate(\n input_id = row_number() - 1,\n row = floor(input_id / length(input)),\n col = floor(input_id %% length(input))\n )\n\n# Convert borders between grid cells to graph vertices and map edges by cell\nborders <- df |> \n mutate(border_e = (cell != \"#\" & lead(cell) != \"#\"), .by = row) |> \n mutate(border_s = (cell != \"#\" & lead(cell) != \"#\"), .by = col) |> \n mutate(\n vtx_id_e = case_when(border_e ~ cumsum(border_e)),\n vtx_id_s = case_when(border_s ~ cumsum(border_s) + max(vtx_id_e, na.rm = T))\n ) |> \n mutate(vtx_id_n = lag(vtx_id_s), .by = col) |> \n mutate(vtx_id_w = lag(vtx_id_e), .by = row) |> \n mutate(\n conn_ns = map2(vtx_id_n, vtx_id_s, ~ na.omit(c(.x, .y))),\n conn_ew = map2(vtx_id_e, vtx_id_w, ~ na.omit(c(.x, .y))),\n conn_ne = map2(vtx_id_n, vtx_id_e, ~ na.omit(c(.x, .y))),\n conn_nw = map2(vtx_id_n, vtx_id_w, ~ na.omit(c(.x, .y))),\n conn_se = map2(vtx_id_s, vtx_id_e, ~ na.omit(c(.x, .y))),\n conn_sw = map2(vtx_id_s, vtx_id_w, ~ na.omit(c(.x, .y))),\n )\n\n# Extract the list of all vertices\nvertices <- c(borders$vtx_id_e, borders$vtx_id_s) |> \n na.omit() |> \n sort()\n\n# Convert vertices and edges to an adjacency matrix\nmtx <- borders |> \n # Unnest lists of edge connections between vertices\n select(starts_with(\"conn\")) |> \n pivot_longer(everything(), names_to = \"conn\", names_prefix = \"conn_\") |> \n unnest_wider(value, names_sep = \"_\") |> \n drop_na(value_1, value_2) |> \n # Rotations get an extra 1k added to the weight\n mutate(weight = case_match(conn, c(\"ns\", \"ew\") ~ 1, .default = 1001)) |> \n select(-conn) |> \n # Convert to matrix format, where unconnected vertices have weight 0\n complete(value_1 = vertices, value_2 = vertices, fill = list(weight = 0)) |> \n arrange(value_1, value_2) |> \n pivot_wider(names_from = value_2, values_from = weight) |> \n column_to_rownames(var = \"value_1\") |> \n as.matrix()\n\n# Make matrix symmetric (for an undirected graph)\nsym_mtx <- pmax(mtx, t(mtx))\n\n# Convert adjacency matrix to a graph\ng <- graph_from_adjacency_matrix(sym_mtx, mode = \"undirected\", weighted = TRUE)\n```\n:::\n\n\n\n\nDetermine possible starting and ending locations from the input\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nspecial_cells <- borders |> \n filter(cell %in% c(\"S\", \"E\")) |> \n select(cell, starts_with(\"vtx_id\")) |> \n pivot_longer(\n starts_with(\"vtx_id\"), \n names_prefix = \"vtx_id_\",\n names_to = \"dir\",\n values_to = \"vertex\"\n ) |> \n drop_na(vertex)\n\n# Create all combinations of start & end cell borders\ncombos <- special_cells |> \n filter(cell == \"S\") |> \n mutate(\n init_rotation = case_match(dir, \"e\" ~ 0, c(\"n\", \"s\") ~ 1, \"w\" ~ 2) * 1000\n ) |>\n select(start_vertex = vertex, init_rotation) |> \n cross_join(\n special_cells |> \n filter(cell == \"E\") |> \n select(end_vertex = vertex)\n )\n```\n:::\n\n\n\n\nFind the minimum path distance for each start/end vertex combo:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nmin_dist <- combos |> \n mutate(\n dist = map2_int(\n start_vertex, \n end_vertex, \n ~ distances(g, .x, .y)) + init_rotation + 1\n ) |> \n slice_min(dist)\n\nmin_dist |> \n pull(dist)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 102504\n```\n\n\n:::\n:::\n\n\n\n\n## Part 2\n\nPull all paths that have the minimum distance from start to end:\n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nshortest_paths <- min_dist |> \n pmap(function(start_vertex, init_rotation, end_vertex, ...) {\n all_shortest_paths(g, start_vertex, end_vertex)$vpaths\n }) |> \n flatten() |> \n map(as.integer)\n\n\npath_vertices <- shortest_paths |> \n unlist() |> \n unique() |> \n sort()\n```\n:::\n\n\n\n\nCount all non-wall cells with a border in the shortest path vertex list: \n\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nborders |> \n select(cell, input_id, starts_with(\"vtx_id\")) |> \n pivot_longer(starts_with(\"vtx_id\")) |> \n drop_na(value) |> \n filter(map_lgl(value, ~ .x %in% path_vertices)) |> \n filter(cell != \"#\") |> \n distinct(input_id) |> \n nrow()\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n[1] 535\n```\n\n\n:::\n:::\n",
+ "supporting": [],
+ "filters": [
+ "rmarkdown/pagebreak.lua"
+ ],
+ "includes": {},
+ "engineDependencies": {},
+ "preserve": {},
+ "postProcess": true
+ }
+}
\ No newline at end of file
diff --git a/adventofcode.Rproj b/adventofcode.Rproj
index e83436a..082ea68 100644
--- a/adventofcode.Rproj
+++ b/adventofcode.Rproj
@@ -1,4 +1,5 @@
Version: 1.0
+ProjectId: 5d9291bd-c9cc-4051-8d5e-982007d0477c
RestoreWorkspace: Default
SaveWorkspace: Default
diff --git a/docs/2022/R/day01.html b/docs/2022/R/day01.html
index 3fc30cd..cb8941d 100644
--- a/docs/2022/R/day01.html
+++ b/docs/2022/R/day01.html
@@ -67,7 +67,7 @@
-
+
@@ -233,6 +233,12 @@
Day 1
+
+
@@ -859,8 +865,8 @@ Part 2
-
diff --git a/docs/2022/R/day02.html b/docs/2022/R/day02.html
index 1cd192a..be0bbd9 100644
--- a/docs/2022/R/day02.html
+++ b/docs/2022/R/day02.html
@@ -233,6 +233,12 @@
Day 2
+
+
diff --git a/docs/2022/R/day03.html b/docs/2022/R/day03.html
index b7d84f6..d0c29d2 100644
--- a/docs/2022/R/day03.html
+++ b/docs/2022/R/day03.html
@@ -233,6 +233,12 @@ Day 3
+
+
diff --git a/docs/2022/R/day04.html b/docs/2022/R/day04.html
index 66c61ee..fc99ea7 100644
--- a/docs/2022/R/day04.html
+++ b/docs/2022/R/day04.html
@@ -233,6 +233,12 @@ Day 4
+
+
diff --git a/docs/2022/R/day05.html b/docs/2022/R/day05.html
index 3e1ee43..1c9ebcd 100644
--- a/docs/2022/R/day05.html
+++ b/docs/2022/R/day05.html
@@ -233,6 +233,12 @@ Day 5
+
+
diff --git a/docs/2022/R/day06.html b/docs/2022/R/day06.html
index 189c23f..ec7ba96 100644
--- a/docs/2022/R/day06.html
+++ b/docs/2022/R/day06.html
@@ -233,6 +233,12 @@ Day 6
+
+
diff --git a/docs/2022/R/day07.html b/docs/2022/R/day07.html
index 53744ad..8fa8874 100644
--- a/docs/2022/R/day07.html
+++ b/docs/2022/R/day07.html
@@ -233,6 +233,12 @@ Day 7
+
+
diff --git a/docs/2022/R/day08.html b/docs/2022/R/day08.html
index 1d0538a..3f774d3 100644
--- a/docs/2022/R/day08.html
+++ b/docs/2022/R/day08.html
@@ -233,6 +233,12 @@ Day 8
+
+
diff --git a/docs/2022/R/day09.html b/docs/2022/R/day09.html
index a88ac8a..eb98d85 100644
--- a/docs/2022/R/day09.html
+++ b/docs/2022/R/day09.html
@@ -233,6 +233,12 @@ Day 9
+
+
diff --git a/docs/2022/R/day10.html b/docs/2022/R/day10.html
index 0073878..1044df5 100644
--- a/docs/2022/R/day10.html
+++ b/docs/2022/R/day10.html
@@ -233,6 +233,12 @@ Day 10
+
+
diff --git a/docs/2022/R/day11.html b/docs/2022/R/day11.html
index fa172f6..9d43f72 100644
--- a/docs/2022/R/day11.html
+++ b/docs/2022/R/day11.html
@@ -233,6 +233,12 @@ Day 11
+
+
diff --git a/docs/2022/R/day12.html b/docs/2022/R/day12.html
index b1df33b..6097add 100644
--- a/docs/2022/R/day12.html
+++ b/docs/2022/R/day12.html
@@ -233,6 +233,12 @@ Day 12
+
+
diff --git a/docs/2022/R/day13.html b/docs/2022/R/day13.html
index 7222b76..faa7b60 100644
--- a/docs/2022/R/day13.html
+++ b/docs/2022/R/day13.html
@@ -233,6 +233,12 @@ Day 13
+
+
diff --git a/docs/2022/R/day14.html b/docs/2022/R/day14.html
index 2ec078e..4251c4b 100644
--- a/docs/2022/R/day14.html
+++ b/docs/2022/R/day14.html
@@ -233,6 +233,12 @@ Day 14
+
+
diff --git a/docs/2022/R/day15.html b/docs/2022/R/day15.html
index 4f9d05c..802dbf4 100644
--- a/docs/2022/R/day15.html
+++ b/docs/2022/R/day15.html
@@ -232,6 +232,12 @@ Day 15
+
+
diff --git a/docs/2024/R/day01.html b/docs/2024/R/day01.html
index 2099a73..b2cdc49 100644
--- a/docs/2024/R/day01.html
+++ b/docs/2024/R/day01.html
@@ -232,6 +232,12 @@ Day 1
+
+
diff --git a/docs/2024/R/day02.html b/docs/2024/R/day02.html
index eefb89d..53545d0 100644
--- a/docs/2024/R/day02.html
+++ b/docs/2024/R/day02.html
@@ -233,6 +233,12 @@ Day 2
+
+
diff --git a/docs/2024/R/day03.html b/docs/2024/R/day03.html
index 4f27025..6755be2 100644
--- a/docs/2024/R/day03.html
+++ b/docs/2024/R/day03.html
@@ -233,6 +233,12 @@ Day 3
+
+
diff --git a/docs/2024/R/day04.html b/docs/2024/R/day04.html
index 463be13..1ce7438 100644
--- a/docs/2024/R/day04.html
+++ b/docs/2024/R/day04.html
@@ -233,6 +233,12 @@ Day 4
+
+
diff --git a/docs/2024/R/day05.html b/docs/2024/R/day05.html
index 5f4fa76..85b3641 100644
--- a/docs/2024/R/day05.html
+++ b/docs/2024/R/day05.html
@@ -233,6 +233,12 @@ Day 5
+
+
diff --git a/docs/2024/R/day06.html b/docs/2024/R/day06.html
index 76dc2a1..a5536eb 100644
--- a/docs/2024/R/day06.html
+++ b/docs/2024/R/day06.html
@@ -233,6 +233,12 @@ Day 6
+
+
diff --git a/docs/2024/R/day07.html b/docs/2024/R/day07.html
index c593b70..e45a327 100644
--- a/docs/2024/R/day07.html
+++ b/docs/2024/R/day07.html
@@ -233,6 +233,12 @@ Day 7
+
+
diff --git a/docs/2024/R/day08.html b/docs/2024/R/day08.html
index bec91f6..f6b4e77 100644
--- a/docs/2024/R/day08.html
+++ b/docs/2024/R/day08.html
@@ -233,6 +233,12 @@ Day 8
+
+
diff --git a/docs/2024/R/day09.html b/docs/2024/R/day09.html
index 12fcbb4..cea5e8d 100644
--- a/docs/2024/R/day09.html
+++ b/docs/2024/R/day09.html
@@ -233,6 +233,12 @@ Day 9
+
+
diff --git a/docs/2024/R/day10.html b/docs/2024/R/day10.html
index 805b190..c48b707 100644
--- a/docs/2024/R/day10.html
+++ b/docs/2024/R/day10.html
@@ -233,6 +233,12 @@ Day 10
+
+
diff --git a/docs/2024/R/day11.html b/docs/2024/R/day11.html
index 0c007fc..bb52bf6 100644
--- a/docs/2024/R/day11.html
+++ b/docs/2024/R/day11.html
@@ -233,6 +233,12 @@ Day 11
+
+
diff --git a/docs/2024/R/day12.html b/docs/2024/R/day12.html
index 69b8a71..c0c03ed 100644
--- a/docs/2024/R/day12.html
+++ b/docs/2024/R/day12.html
@@ -233,6 +233,12 @@ Day 12
+
+
diff --git a/docs/2024/R/day13.html b/docs/2024/R/day13.html
index d82b638..523a3f1 100644
--- a/docs/2024/R/day13.html
+++ b/docs/2024/R/day13.html
@@ -233,6 +233,12 @@ Day 13
+
+
diff --git a/docs/2024/R/day14.html b/docs/2024/R/day14.html
index 8cef5c0..5e732da 100644
--- a/docs/2024/R/day14.html
+++ b/docs/2024/R/day14.html
@@ -233,6 +233,12 @@ Day 14
+
+
diff --git a/docs/2024/R/day15.html b/docs/2024/R/day15.html
index 3ed8b80..1162632 100644
--- a/docs/2024/R/day15.html
+++ b/docs/2024/R/day15.html
@@ -66,7 +66,7 @@
-
+
@@ -233,6 +233,12 @@ Day 15
+
+
@@ -349,6 +355,7 @@ Contents
@@ -481,6 +488,133 @@ Part 1
[1] 1457740
+
+
+Part 2
+Widen the map:
+
+
# Convert WH input text to a matrix
+ mtx <- input_wh |>
+ str_replace_all ("#" , "##" ) |>
+ str_replace_all ("O" , "[]" ) |>
+ str_replace_all (" \\ ." , ".." ) |>
+ str_replace_all ("@" , "@." ) |>
+ str_split ("" ) |>
+ matrix () |>
+ unlist () |>
+ matrix (byrow = TRUE , nrow = length (input_wh))
+
+Define functions to move boxes around the map:
+
+
get_box_coords <- function (mtx, box_num) {
+ as_tibble (which (mtx == box_num, arr.ind = TRUE ))
+ }
+
+ get_next_coords <- function (cur_coords, dir = c ("<" , "^" , ">" , "v" )) {
+ cur_coords |>
+ mutate (
+ row = row + case_match (dir, "^" ~ - 1 , "v" ~ 1 , .default = 0 ),
+ col = col + case_match (dir, "<" ~ - 1 , ">" ~ 1 , .default = 0 ),
+ )
+ }
+
+ get_next_chrs <- function (mtx, cur_coords, dir = c ("<" , "^" , ">" , "v" )) {
+ # Pull the values of the next cells in the intended direction
+ cur_coords |>
+ get_next_coords (dir) |>
+ mutate (chr = map2_chr (row, col, ~ mtx[.x, .y])) |>
+ anti_join (cur_coords, join_by (row, col)) |>
+ pull (chr) |>
+ unique ()
+ }
+
+ is_blocked <- function (mtx, box_num, dir = c ("<" , "^" , ">" , "v" )) {
+
+ cur <- get_box_coords (mtx, box_num)
+ nxt_chrs <- get_next_chrs (mtx, cur, dir)
+
+ # Test if the current box is completely blocked or completely free
+ if (any (nxt_chrs == '#' ))
+ return (TRUE )
+ else if (all (nxt_chrs == '.' ))
+ return (FALSE )
+
+ # Recurse across all later boxes
+ nxt_chrs |>
+ keep (~ str_detect (.x, "^ \\ d+$" )) |>
+ map_lgl (~ is_blocked (mtx, .x, dir)) |>
+ any ()
+ }
+
+ move_box <- function (mtx, box_num, dir = c ("<" , "^" , ">" , "v" )) {
+ # Get the coordinates of the current box and the place it'll move to
+ cur <- get_box_coords (mtx, box_num)
+ nxt <- get_next_coords (cur, dir)
+
+ # Move all downstream boxes before moving self
+ next_boxes <- get_next_chrs (mtx, cur, dir) |>
+ keep (~ str_detect (.x, "^ \\ d+$" ))
+
+ for (box in next_boxes) {
+ mtx <- move_box (mtx, box, dir)
+ }
+
+ # # Replace the current coords with "." and the next coords with the box
+ mtx[cur$ row, cur$ col] <- "."
+ mtx[nxt$ row, nxt$ col] <- box_num
+
+ return (mtx)
+ }
+
+Loop through puzzle input:
+
+
run_simulation <- function (mtx, move_seq) {
+ # Convert boxes from format "[]" into ID numbers unique to each box:
+ coords <- list (l = which (mtx == "[" ), r = which (mtx == "]" ))
+ for (i in 1 : length (coords$ l)) {
+ mtx[coords$ l[i]] <- i
+ mtx[coords$ r[i]] <- i
+ }
+
+ # Loop through sequence of moves and apply to the map
+ mtx_prv <- mtx
+ for (dir in move_seq) {
+ if (! is_blocked (mtx_prv, box_num = "@" , dir = dir)) {
+ mtx_new <- move_box (mtx_prv, box_num = "@" , dir = dir)
+ mtx_prv <- mtx_new
+ }
+ }
+
+ return (mtx_new)
+ }
+
+ output <- run_simulation (mtx, move_seq)
+
+Convert the result to GPS coordinates:
+
+
output |>
+ as_tibble () |>
+ mutate (row = row_number (), .before = everything ()) |>
+ pivot_longer (
+ - row,
+ names_to = "col" ,
+ names_prefix = "V" ,
+ names_transform = as.integer
+ ) |>
+ # Select only the leftmost cell of each boxes
+ filter (str_detect (value, " \\ d+" )) |>
+ slice_min (col, by = value) |>
+ mutate (
+ dist_top = row - 1 ,
+ dist_left = col - 1 ,
+ gps = 100 * dist_top + dist_left
+ ) |>
+ pull (gps) |>
+ sum ()
+
+
@@ -910,8 +1044,8 @@ Part 1
-
diff --git a/docs/2024/R/day16.html b/docs/2024/R/day16.html
new file mode 100644
index 0000000..2650208
--- /dev/null
+++ b/docs/2024/R/day16.html
@@ -0,0 +1,984 @@
+
+
+
+
+
+
+
+
+
+
+
+Day 16 – Advent of Code: Worked Solutions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Setup
+
+
# Libraries
+library (tidyverse)
+library (igraph)
+
+# Read input from file
+ input <- read_lines ("../input/day16.txt" , skip_empty_rows = TRUE )
+
+
+
+Part 1
+Convert text input into a weighted, undirected graph
+
+
# Convert input to a data frame
+ df <- input |>
+ str_split ("" ) |>
+ unlist () |>
+ as_tibble_col (column_name = "cell" ) |>
+ mutate (
+ input_id = row_number () - 1 ,
+ row = floor (input_id / length (input)),
+ col = floor (input_id %% length (input))
+ )
+
+# Convert borders between grid cells to graph vertices and map edges by cell
+ borders <- df |>
+ mutate (border_e = (cell != "#" & lead (cell) != "#" ), .by = row) |>
+ mutate (border_s = (cell != "#" & lead (cell) != "#" ), .by = col) |>
+ mutate (
+ vtx_id_e = case_when (border_e ~ cumsum (border_e)),
+ vtx_id_s = case_when (border_s ~ cumsum (border_s) + max (vtx_id_e, na.rm = T))
+ ) |>
+ mutate (vtx_id_n = lag (vtx_id_s), .by = col) |>
+ mutate (vtx_id_w = lag (vtx_id_e), .by = row) |>
+ mutate (
+ conn_ns = map2 (vtx_id_n, vtx_id_s, ~ na.omit (c (.x, .y))),
+ conn_ew = map2 (vtx_id_e, vtx_id_w, ~ na.omit (c (.x, .y))),
+ conn_ne = map2 (vtx_id_n, vtx_id_e, ~ na.omit (c (.x, .y))),
+ conn_nw = map2 (vtx_id_n, vtx_id_w, ~ na.omit (c (.x, .y))),
+ conn_se = map2 (vtx_id_s, vtx_id_e, ~ na.omit (c (.x, .y))),
+ conn_sw = map2 (vtx_id_s, vtx_id_w, ~ na.omit (c (.x, .y))),
+ )
+
+# Extract the list of all vertices
+ vertices <- c (borders$ vtx_id_e, borders$ vtx_id_s) |>
+ na.omit () |>
+ sort ()
+
+# Convert vertices and edges to an adjacency matrix
+ mtx <- borders |>
+ # Unnest lists of edge connections between vertices
+ select (starts_with ("conn" )) |>
+ pivot_longer (everything (), names_to = "conn" , names_prefix = "conn_" ) |>
+ unnest_wider (value, names_sep = "_" ) |>
+ drop_na (value_1, value_2) |>
+ # Rotations get an extra 1k added to the weight
+ mutate (weight = case_match (conn, c ("ns" , "ew" ) ~ 1 , .default = 1001 )) |>
+ select (- conn) |>
+ # Convert to matrix format, where unconnected vertices have weight 0
+ complete (value_1 = vertices, value_2 = vertices, fill = list (weight = 0 )) |>
+ arrange (value_1, value_2) |>
+ pivot_wider (names_from = value_2, values_from = weight) |>
+ column_to_rownames (var = "value_1" ) |>
+ as.matrix ()
+
+# Make matrix symmetric (for an undirected graph)
+ sym_mtx <- pmax (mtx, t (mtx))
+
+# Convert adjacency matrix to a graph
+ g <- graph_from_adjacency_matrix (sym_mtx, mode = "undirected" , weighted = TRUE )
+
+Determine possible starting and ending locations from the input
+
+
special_cells <- borders |>
+ filter (cell %in% c ("S" , "E" )) |>
+ select (cell, starts_with ("vtx_id" )) |>
+ pivot_longer (
+ starts_with ("vtx_id" ),
+ names_prefix = "vtx_id_" ,
+ names_to = "dir" ,
+ values_to = "vertex"
+ ) |>
+ drop_na (vertex)
+
+# Create all combinations of start & end cell borders
+ combos <- special_cells |>
+ filter (cell == "S" ) |>
+ mutate (
+ init_rotation = case_match (dir, "e" ~ 0 , c ("n" , "s" ) ~ 1 , "w" ~ 2 ) * 1000
+ ) |>
+ select (start_vertex = vertex, init_rotation) |>
+ cross_join (
+ special_cells |>
+ filter (cell == "E" ) |>
+ select (end_vertex = vertex)
+ )
+
+Find the minimum path distance for each start/end vertex combo:
+
+
min_dist <- combos |>
+ mutate (
+ dist = map2_int (
+ start_vertex,
+ end_vertex,
+ ~ distances (g, .x, .y)) + init_rotation + 1
+ ) |>
+ slice_min (dist)
+
+ min_dist |>
+ pull (dist)
+
+
+
+
+Part 2
+Pull all paths that have the minimum distance from start to end:
+
+
shortest_paths <- min_dist |>
+ pmap (function (start_vertex, init_rotation, end_vertex, ...) {
+ all_shortest_paths (g, start_vertex, end_vertex)$ vpaths
+ }) |>
+ flatten () |>
+ map (as.integer)
+
+
+ path_vertices <- shortest_paths |>
+ unlist () |>
+ unique () |>
+ sort ()
+
+Count all non-wall cells with a border in the shortest path vertex list:
+
+
borders |>
+ select (cell, input_id, starts_with ("vtx_id" )) |>
+ pivot_longer (starts_with ("vtx_id" )) |>
+ drop_na (value) |>
+ filter (map_lgl (value, ~ .x %in% path_vertices)) |>
+ filter (cell != "#" ) |>
+ distinct (input_id) |>
+ nrow ()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
index 4daa3f7..889a777 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -7,7 +7,7 @@
-
+
Advent of Code: Worked Solutions