-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
3,599 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
--- | ||
title: "Day 12" | ||
date: 2024-12-12 | ||
author: | ||
name: https://adventofcode.com/2024/day/12 | ||
url: https://adventofcode.com/2024/day/12 | ||
--- | ||
|
||
## Setup | ||
|
||
```{r setup} | ||
# Libraries | ||
library(tidyverse) | ||
library(igraph) | ||
# Read input from file into a data frame | ||
input <- read_table("../input/day12.txt", col_names = "chr") |> | ||
mutate( | ||
row = row_number(), | ||
chr = str_split(chr, "") | ||
) |> | ||
unnest(chr) |> | ||
mutate(col = row_number(), .by = row) |> | ||
mutate(idx = row_number(), .before = everything()) | ||
``` | ||
|
||
## Part 1 | ||
|
||
Format the input as a graph, with edges connecting neighbors of the same type: | ||
|
||
```{r} | ||
# Flag neighboring characters of the same value that border one other | ||
edges_wide <- input |> | ||
mutate(v = case_when(row + 1 == lead(row) ~ lead(idx)), .by = c(chr, col)) |> | ||
mutate(h = case_when(col + 1 == lead(col) ~ lead(idx)), .by = c(chr, row)) | ||
edges_long <- edges_wide |> | ||
pivot_longer( | ||
c(v, h), | ||
names_to = NULL, | ||
values_to = "target", | ||
values_drop_na = TRUE | ||
) | ||
# Format neighbors as a list of edges and add to add a graph | ||
g <- edges_long |> | ||
transmute( | ||
edge_id = row_number(), | ||
src = idx, | ||
target | ||
) |> | ||
pivot_longer(c(src, target)) |> | ||
arrange(edge_id, value) |> | ||
pull(value) |> | ||
make_graph(n = nrow(input), directed = FALSE) | ||
V(g)$name <- 1:nrow(input) | ||
# Separate out the resulting graph into sub-graphs of innerconnected regions | ||
dg <- decompose(g) | ||
``` | ||
|
||
Compute the perimeter, area, and cost of each subgraph then sum the total: | ||
|
||
```{r} | ||
dg |> | ||
map_int(\(subgraph) { | ||
perim <- sum(4 - degree(subgraph)) | ||
area <- gorder(subgraph) | ||
perim * area | ||
}) |> | ||
sum() | ||
``` | ||
|
||
## Part 2 | ||
|
||
Used a hint from reddit: the number of corners is equal to the number of sides. | ||
|
||
A plot can have a convex corner or a concave corner. | ||
|
||
- A cell has a convex corner for each pair of adjacent borders | ||
- A cell has a concave corner if it has two adjacent cells of its same group, but its diagonal cell between the two has a different group. | ||
|
||
```{r} | ||
# Get original row/column input and join on the group output from the graph | ||
groups <- left_join( | ||
input, | ||
imap_dfr(dg, \(g, grp_idx) tibble(grp = grp_idx, idx = V(g)$name)), | ||
join_by(idx) | ||
) |> | ||
select(idx, grp, row, col) | ||
# For each of a cell's neighbors, flag if they're in the same group | ||
neighbors <- groups |> | ||
# Get group number of each adjacent cell (N/S/E/W) | ||
left_join(transmute(groups, n = grp, row = row + 1, col), join_by(row, col)) |> | ||
left_join(transmute(groups, w = grp, col = col + 1, row), join_by(row, col)) |> | ||
left_join(transmute(groups, s = grp, row = row - 1, col), join_by(row, col)) |> | ||
left_join(transmute(groups, e = grp, col = col - 1, row), join_by(row, col)) |> | ||
# Get group number of each diagonal cell (NW/NE/SW/SE) | ||
left_join(transmute(groups, nw = grp, row = row + 1, col = col + 1), join_by(row, col)) |> | ||
left_join(transmute(groups, ne = grp, row = row + 1, col = col - 1), join_by(row, col)) |> | ||
left_join(transmute(groups, sw = grp, row = row - 1, col = col + 1), join_by(row, col)) |> | ||
left_join(transmute(groups, se = grp, row = row - 1, col = col - 1), join_by(row, col)) |> | ||
select(-c(row, col)) |> | ||
# Compare group numbers of adjacent/diagonal cells to the current cell | ||
mutate(across(c(n, w, s, e, nw, ne, sw, se), ~ replace_na(.x == grp, FALSE))) | ||
# Compute total number of concave/convex corners for each cell | ||
corners <- neighbors |> | ||
mutate( | ||
convex = (!n & !w) + (!s & !w) + (!s & !e) + (!n & !e), | ||
concave = (n & w & !nw) + (s & w & !sw) + (s & e & !se) + (n & e & !ne) | ||
) | ||
``` | ||
|
||
Total the number of corners per group and multiply by the group's area to get the total cost: | ||
|
||
```{r} | ||
corners |> | ||
summarize( | ||
area = n(), | ||
num_sides = sum(convex + concave), | ||
.by = grp | ||
) |> | ||
mutate(cost = area * num_sides) |> | ||
pull(cost) |> | ||
sum() | ||
``` | ||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
--- | ||
title: "Day 13" | ||
date: 2024-12-13 | ||
author: | ||
name: https://adventofcode.com/2024/day/13 | ||
url: https://adventofcode.com/2024/day/13 | ||
--- | ||
|
||
## Setup | ||
|
||
```{r setup} | ||
# Libraries | ||
library(tidyverse) | ||
library(unglue) | ||
# Read input from file | ||
input <- read_lines("../input/day13.txt", skip_empty_rows = TRUE) | ||
``` | ||
|
||
## Part 1 | ||
|
||
Extract numerical values from input text: | ||
```{r} | ||
df <- input |> | ||
unglue_data(c( | ||
"Button {button}: X+{x=\\d+}, Y+{y=\\d+}", | ||
"{button}: X={x=\\d+}, Y={y=\\d+}" | ||
)) |> | ||
mutate( | ||
machine_id = floor((row_number() - 1) / 3), | ||
across(c(x, y), parse_number), | ||
.before = everything() | ||
) |> | ||
pivot_wider(names_from = button, values_from = c(x, y)) | ||
``` | ||
|
||
|
||
Define a function to convert numeric equation input and output token counts: | ||
|
||
```{r} | ||
compute_tokens <- function(df) { | ||
# Convert each machine's properties into a system of equations and solve. | ||
soln <- df |> | ||
nest(coeff = c(x_A, x_B, y_A, y_B)) |> | ||
nest(intercept = c(x_Prize, y_Prize)) |> | ||
mutate( | ||
coeff = map(coeff, ~ matrix(as.numeric(.x), nrow = 2, byrow = TRUE)), | ||
intercept = map(intercept, as.numeric), | ||
soln = map2( | ||
coeff, | ||
intercept, | ||
~ solve(.x, .y) |> | ||
set_names("A", "B") |> | ||
as_tibble_row() | ||
) | ||
) |> | ||
unnest(soln) |> | ||
select(machine_id, A, B) | ||
# Check that the solution is two whole numbers, then sum the token cost | ||
soln |> | ||
mutate( | ||
across( | ||
c(A, B), | ||
~ near(.x, abs(round(.x)), tol = 0.001), | ||
.names = "{.col}_valid" | ||
), | ||
win = A_valid & B_valid, | ||
tokens = if_else(win, 3 * A + B, 0) | ||
) |> | ||
pull(tokens) |> | ||
sum() | ||
} | ||
``` | ||
|
||
Run function on puzzle input: | ||
|
||
```{r} | ||
compute_tokens(df) | ||
``` | ||
|
||
|
||
## Part 2 | ||
|
||
Add 10000000000000 to each prize intercept and re-compute: | ||
|
||
```{r} | ||
df |> | ||
mutate(across(c(x_Prize, y_Prize), ~ .x + 10000000000000)) |> | ||
compute_tokens() |> | ||
format(scientific = FALSE) | ||
``` | ||
|
Oops, something went wrong.