Day 8

Advent of Code: Worked Solutions

About
Date

December 8, 2024

Setup

Import libraries:

library(tidyverse)

Read input from file:

input <- read_lines("../input/day08.txt")

Convert text input to a character matrix:

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

Part 1

Define a helper function to check if a coordinate x is within the bounds of the map (mtx):

in_bounds <- \(x, map) between(x[1], 1, nrow(map)) & between(x[2], 1, ncol(map))

Define a helper function to compute the antinodes of a given pair of antenna coordinates on a map:

antinode_pair <- function(x1, x2, map) {
  diff <- x2 - x1
  keep(list(x1 - diff, x2 + diff), ~ in_bounds(.x, map))
}

Define a helper function to get the coordinates of every antenna of a given frequency on a map:

get_antennas <- function(freq, map) {
  antennas <- which(map == freq, arr.ind = TRUE)
  split(antennas, row(antennas))
}

Define a function to compute all antinodes of a given frequency in a map:

get_all_antinodes <- function(freq, map, f) {
  antennas <- get_antennas(freq, map)
  
  pairs <- combn(antennas, 2)
  pairs <- split(pairs, col(pairs))
  
  pairs |> 
    map(~ f(.x[[1]], .x[[2]], map)) |> 
    list_flatten() |> 
    unique()
}

Compute the distinct set of frequencies in the map:

freqs <- mtx |>
  as.vector() |>
  unique() |> 
  keep(~ .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()

Part 2

Update the antinode function which computes the antidotes 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()