My 2024 Solutions

Day 1

Part 1

input <- readr::read_delim(
  "2024/01-input", 
  delim = "   ", 
  col_names = FALSE,
  show_col_types = FALSE
)

sum(abs(sort(input$X1) - sort(input$X2)))
0.076 sec elapsed

Part 2

input <- readr::read_delim(
  "2024/01-input", 
  delim = "   ", 
  col_names = FALSE,
  show_col_types = FALSE
)

counts <- table(input$X2)[as.character(input$X1)]

sum(abs(input$X1 * counts), na.rm = TRUE)
0.005 sec elapsed

Day 2

Part 1

read_list <- function(path, sep = "", type = identity) {
  lines <- readLines(path)
  res <- strsplit(lines, sep)
  res <- lapply(res, type)
  res
}

input <- read_list("2024/02-input", " ", as.integer)

safe <- function(x) {
  diffs <- diff(x)
  cond1 <- all(diffs > 0) || all(diffs < 0)
  cond2 <- all(abs(diffs) >= 1) && all(abs(diffs) <= 3)
  cond1 && cond2
}

vapply(input, safe, logical(1)) |>
  sum()
0.033 sec elapsed

Part 2

read_list <- function(path, sep = "", type = identity) {
  lines <- readLines(path)
  res <- strsplit(lines, sep)
  res <- lapply(res, type)
  res
}

input <- read_list("2024/02-input", " ", as.integer)

safe <- function(x) {
  diffs <- diff(x)
  cond1 <- all(diffs > 0) || all(diffs < 0)
  cond2 <- all(abs(diffs) >= 1) && all(abs(diffs) <= 3)
  cond1 && cond2
}

skip_safe <- function(x) {
  is_safe <- FALSE
  for (i in seq_along(x)) {
    if (safe(x[-i])) {
      is_safe <- TRUE
      break
    }
  }
  is_safe
}

vapply(input, skip_safe, logical(1)) |>
  sum()
0.024 sec elapsed

Day 3

Part 1

input <- readLines("2024/03-input") |>
  paste0(collapse = "")

mul <- function(x, y) x * y

input |>
  stringr::str_extract_all("mul\\(\\d+,\\d+\\)") |>
  unlist() |>
  purrr::map_int(\(x) eval(parse(text = x))) |>
  sum()
0.024 sec elapsed

Part 2

input <- readLines("2024/03-input") |>
  paste0(collapse = "")

mul <- function(x, y) x * y

input |>
  stringr::str_remove_all("don't\\(\\).*?do\\(\\)") |>
  stringr::str_extract_all("mul\\(\\d+,\\d+\\)") |>
  unlist() |>
  purrr::map_int(\(x) eval(parse(text = x))) |>
  sum()
0.015 sec elapsed

Day 4

Part 1

read_matrix <- function(path, sep = "", fill = NA, type = identity) {
  lines <- readLines(path)
  tokens <- strsplit(lines, sep)
  token_lengths <- lengths(tokens)
  res <- matrix(fill, nrow = length(lines), ncol = max(token_lengths))

  for (i in seq_along(lines)) {
    res[i, seq_len(token_lengths[i])] <- type(tokens[[i]])
  }
  res
}

input <- read_matrix("2024/04-input")

up <- apply(input, 1, identity, simplify = FALSE)
down <- lapply(up, rev)
left <- apply(input, 2, identity, simplify = FALSE)
right <- lapply(left, rev)

nrow <- nrow(input)

diag1 <- purrr::map(seq(-nrow - 1, nrow - 1), \(i) input[row(input) == (col(input) + i)])
diag2 <- purrr::map(seq(2, nrow * 2), \(i) input[row(input) + col(input) == i])

diag3 <- lapply(diag1, rev)
diag4 <- lapply(diag2, rev)

c(left, right, up, down, diag1, diag2, diag3, diag4) |>
  purrr::map_chr(\(x) paste(x, collapse = "")) |>
  stringr::str_count("XMAS") |>
  sum()
0.119 sec elapsed

Part 2

read_matrix <- function(path, sep = "", fill = NA, type = identity) {
  lines <- readLines(path)
  tokens <- strsplit(lines, sep)
  token_lengths <- lengths(tokens)
  res <- matrix(fill, nrow = length(lines), ncol = max(token_lengths))

  for (i in seq_along(lines)) {
    res[i, seq_len(token_lengths[i])] <- type(tokens[[i]])
  }
  res
}

input <- read_matrix("2024/04-input")

a_loc <- reshape2::melt(input == "A") |>
  dplyr::filter(value)

count <- 0

for (i in seq_len(nrow(a_loc))) {
  vals <- a_loc[i, ]
  x <- vals$Var1
  y <- vals$Var2

  if (x == 1 || x == nrow(input) || y == 1 || y == nrow(input)) {
    next
  }
  
  x_values <- paste0(
    input[x + 1, y + 1], input[x + 1, y - 1], 
    input[x - 1, y - 1], input[x - 1, y + 1],
    collapse = ""
  )
  
  valid <- c("MMSS", "MSSM", "SSMM", "SMMS")


  if (x_values %in% valid) {
    count <- count + 1
  }
}

count
0.117 sec elapsed

Day 5

Part 1

input <- readLines("2024/05-input")

sep <- which(input == "")

rules <- input[seq(1, sep - 1)] |>
  strsplit("\\|") |>
  lapply(as.integer)
updates <- input[seq(sep + 1, length(input))] |>
  strsplit(",") |>
  lapply(as.integer)

pass_rule <- function(rule, update) {
  order <- diff(match(rule, update))

  is.na(order) || order > 0
}

pass_rules <- function(update, rules) {
  all(vapply(rules, pass_rule, logical(1), update = update))
}

which_passes <- vapply(updates, pass_rules, logical(1), rules)

get_middle <- function(x) {
  mid <- length(x) / 2 + 1
  x[mid]
}

updates[which_passes] |>
  lapply(get_middle) |>
  unlist() |>
  sum()
0.812 sec elapsed

Part 2

input <- readLines("2024/05-input")

sep <- which(input == "")

rules <- input[seq(1, sep - 1)] |>
  strsplit("\\|") |>
  lapply(as.integer)
updates <- input[seq(sep + 1, length(input))] |>
  strsplit(",") |>
  lapply(as.integer)

pass_rule <- function(rule, update) {
  order <- diff(match(rule, update))

  is.na(order) || order > 0
}

pass_rules <- function(update, rules) {
  all(vapply(rules, pass_rule, logical(1), update = update))
}

which_passes <- vapply(updates, pass_rules, logical(1), rules)

get_middle <- function(x) {
  mid <- length(x) / 2 + 1
  x[mid]
}

uncorrect <- updates[!which_passes]

fix_order <- function(rule, update) {
  matches <- match(rule, update)
  before <- matches[1]
  after <- matches[2]
  
  before_inds <- setdiff(seq(1, before), after)
  
  after_inds <- setdiff(seq_along(update), c(before_inds, after))
  
  new_order <- c(before_inds, after, after_inds)
  update[new_order]
}

fix_update <- function(update, rules) {
  while (!pass_rules(update, rules)) {
    for (rule in rules) {
      if (pass_rule(rule, update)) {
        next
      }
      update <- fix_order(rule, update)
    }
  }
  update
}

uncorrect |>
  lapply(fix_update, rules) |>
  lapply(get_middle) |>
  unlist() |>
  sum()
2.77 sec elapsed

Day 6

Day 7

Day 8

Day 9

Day 10

Day 11

Day 12

Day 13

Day 14

Day 15

Day 16

Day 17

Day 18

Day 19

Day 20

Day 21

Day 22

Day 23

Day 24

Day 25