Day 13

Advent of Code: Worked Solutions

About
Date

December 13, 2024

Setup

Import libraries:

library(tidyverse)
library(unglue)

Disable scientific formatting when displaying large numbers:

options(scipen = 999)

Read input from file:

input <- read_lines("../input/day13.txt", skip_empty_rows = TRUE)

Extract numerical values from text input into a data frame:

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))

Part 1

Define a function to convert numeric equation input and output token counts:

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:

compute_tokens(df)

Part 2

Add 10000000000000 to each prize intercept and re-compute:

df |> 
  mutate(across(c(x_Prize, y_Prize), ~ .x + 10000000000000)) |> 
  compute_tokens()