Day 8

Advent of Code: Worked Solutions

About
Date

December 8, 2024

Setup

# Libraries
library(tidyverse)

# Read input from file
input <- read_lines("../input/day08.txt", skip_empty_rows = TRUE)

Part 1

Define antinode functions:

# Check if a coordinate is in the bounds of the map
in_bounds <- function(x, map) {
  between(x[1], 1, nrow(map)) & between(x[2], 1, ncol(map))
}

# Compute the antinodes of a given pair of antennas
antinode_pair <- function(x1, x2, map) {
  diff <- x2 - x1
  list(x1 - diff, x2 + diff) |> 
    keep(~in_bounds(.x, map))
}

# Get coordinates of every antenna of the given frequency
get_freq_antennas <- function(freq, map) {
  antennas <- which(map == freq, arr.ind = TRUE)
  split(antennas, row(antennas))
}

# Compute all antinodes of a given frequency in a given map
get_all_antinodes <- function(freq, map, f) {
  antennas <- get_freq_antennas(freq, map)
  
  pairs <- combn(antennas, 2)
  pairs <- split(pairs, col(pairs))
  
  pairs |> 
    map(~f(.x[[1]], .x[[2]], map)) |> 
    list_flatten() |> 
    unique()
}

Run antinode functions on puzzle input:

# Convert input to matrix format
mtx <- input |>
  str_split("") |> 
  unlist() |> 
  matrix(nrow = length(input), byrow = TRUE)

# Find the distinct set of frequencies in the map
freqs <- keep(
  unique(as.vector(mtx)), 
  ~.x %in% c(letters, LETTERS, as.character(0:9))
)

# Count all distinct antinode locations across all frequencies in the map
freqs |> 
  map(~get_all_antinodes(.x, mtx, antinode_pair)) |> 
  list_flatten() |> 
  unique() |> 
  length()
[1] 369

Part 2

Update the antinode function:

# Compute the updated antinodes of a given pair of antennas
antinode_set <- function(x1, x2, map) {
  diff <- x2 - x1
  antinodes <- list(x1, x2)
  
  i <- 1
  while(in_bounds(x2 + i * diff, map)) {
    antinodes <- c(antinodes, list(as.integer(x2 + i * diff)))
    i <- i + 1
  }

  i <- 1
  while(in_bounds(x1 - i * diff, map)) {
    antinodes <- c(antinodes, list(as.integer(x1 - i * diff)))
    i <- i + 1
  }
  
  antinodes
}

Re-run puzzle input:

freqs |> 
  map(~get_all_antinodes(.x, mtx, antinode_set)) |> 
  list_flatten() |> 
  unique() |> 
  length()
[1] 1169