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

Day 15 + + @@ -859,8 +865,8 @@

Part 2

@@ -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()
+
+
[1] 1467145
+
+
@@ -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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+ + +
+ + + +
+ +
+
+

Day 16

+

Advent of Code: Worked Solutions

+
+ + + +
+ +
+
About
+ +
+ +
+
Date
+
+

December 16, 2024

+
+
+ + +
+ + + +
+ + +
+

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)
+
+
[1] 102504
+
+
+
+
+

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()
+
+
[1] 535
+
+
+ + +
+ +
+ + +
+ + + + + \ 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