03: Gear Ratios

library(mistlecode)

options(scipen = 999)
dt <- 
  readLines("input.txt") |>
  stringr::str_split("")

m <- matrix(unlist(dt), nrow = length(dt), byrow = TRUE)

Part 1

This was so much fun! I love dbscan with all my heart. I also did something really stupid and submitted the test input then had to wait the longest minute of my life to submit the real answer.

dt <- mistlecode::matrix_to_coords(m)
clust <-
  dt |>
  dplyr::filter(data != ".") |>
  dplyr::select(-data) |>
  dbscan::dbscan(sqrt(2), minPts = 2)
dt <- 
  dt |>
  dplyr::filter(data != ".") |>
  dplyr::mutate(clust = clust$cluster) |>
  dplyr::filter(any(!grepl('[0-9]', data)), .by = 'clust')
numbers <-
  mistlecode::coords_to_matrix(dt$data, dt$row, dt$col) |>
  t() |>
  as.vector() |>
  paste0(collapse = "") |>
  stringr::str_replace_all('[^0-9]', ' ') |>
  stringr::str_split(' ') |>
  unlist() |>
  as.numeric() |>
  purrr::discard(is.na)
sum(numbers, na.rm = TRUE)
[1] 520019

Part 2

This is really long-winded. I’m sure it could be better functionalized. The hard part wasn’t as much figuring out what goes in a group as much as figuring out what goes in which group.

dt <- mistlecode::matrix_to_coords(m)
number_clust <-
  dt |>
  dplyr::filter(grepl('[0-9]', data)) |>
  dplyr::select(-data) |>
  dbscan::dbscan(1, minPts = 1)
number_dt <-
  dt |>
  dplyr::filter(grepl('[0-9]', data)) |>
  dplyr::mutate(number_clust = number_clust$cluster)
clust_dt <- 
  dt |>
  dplyr::filter(data != ".") |>
  dplyr::mutate(clust = clust$cluster) |>
  dplyr::left_join(number_dt, by = dplyr::join_by(data, row, col)) |>
  dplyr::filter(any(!grepl('[0-9]', data)), .by = 'clust') |>
  dplyr::mutate(
    has_prod = any(data == '*') & length(unique(number_clust[!is.na(number_clust)])) == 2,
    prod_group = dplyr::cur_group_id(),
    .by = 'clust'
  ) |>
  dplyr::filter(grepl('[0-9]', data))
has_prod <-
  mistlecode::coords_to_matrix(clust_dt$prod_group, clust_dt$row, clust_dt$col) |>
  t() |>
  as.vector() |>
  data.frame() |>
  `colnames<-`('has_prod') |>
  dplyr::mutate(t = cumsum(is.na(has_prod))) |>
  dplyr::filter(dplyr::row_number() == dplyr::n() & !is.na(has_prod), .by = 't') |>
  dplyr::pull(has_prod)

data.frame(
  has_prod,
  numbers
) |>
  dplyr::filter(dplyr::n() >= 2, .by = has_prod) |>
  dplyr::summarise(val = prod(numbers), .by = has_prod) |>
  dplyr::pull(val) |>
  sum()
[1] 75519888