2025

Learning from my issues with floor division on day 1, I went straight to trying every possible string chunk for day 2. Good enough! After seeing the simplicity of regex solutions later, I went ahead and replaced my part 2 solution with that.

I do find “brute force” to be easier with Python than R, but I guess my brain jumps to for loops too much before vectorised and *apply/map operations. It feels easier to me to reason about an item/index in an iterable.

— R Day 2 Part 1 —

solve_day2_part1 <- function(input) {
  # back to one line
  ranges <- paste0(input, collapse = "")
  ranges <- strsplit(ranges, ",", fixed = TRUE) |>
    unlist()

  ranges <- strsplit(ranges, "-", fixed = TRUE)

  invalid_total <- 0L

  for (range in ranges) {
    ids <- range[[1]]:range[[2]]

    is_invalid <- vapply(ids, is_invalid, logical(1))

    invalid_total <- invalid_total + sum(ids[is_invalid])
  }

  invalid_total
}

is_invalid <- function(id) {
  nchars <- nchar(id)

  if (nchars %% 2 == 1) {
    return(FALSE)
  }

  split <- nchars %/% 2

  substr(id, 1, split) == substr(id, split + 1, nchars)
}
Run
aoc_source(day = 2, part = 1)

input = aoc_read(day = 2)

aoc_run(solve_day2_part1(input))
Elapsed: 11.187 seconds
Memory:  19687 KB

— R Day 2 Part 2 —

solve_day2_part2 <- function(input) {
  ranges <- paste0(input, collapse = "")
  ranges <- strsplit(ranges, ",", fixed = TRUE) |>
    unlist()

  ranges <- strsplit(ranges, "-", fixed = TRUE)

  invalid_total <- 0

  ids <- lapply(ranges, \(x) x[[1L]]:x[[2L]]) |>
    unlist()

  is_invalid <- stringi::stri_detect(ids, regex = "^(\\d+)\\1+$")

  sum(ids[is_invalid])
}
Run
aoc_source(day = 2, part = 2)

input = aoc_read(day = 2)

aoc_run(solve_day2_part2(input))
Elapsed: 2.842 seconds
Memory:  44815 KB

— Python Day 2 Part 1 —

def solve_day2_part1(text):
  ranges = text[0].split(",")
  ranges = [str.split("-") for str in ranges]

  invalid_total = 0

  for nums in ranges:
    for i in range(int(nums[0]), int(nums[1])+1):
      i = str(i)
      nchars = len(i)

      if (nchars % 2 != 0):
        continue

      split = nchars // 2

      if i[:split] == i[split:]:
        invalid_total += int(i)

  return(invalid_total)
Run
aoc_source(day = 2, part = 1)

input = aoc_read(day = 2)

result = aoc_run("solve_day2_part1(input)")
Elapsed: 3.739 seconds
Memory:  20 KB

— Python Day 2 Part 2 —

def solve_day2_part2(text):
  ranges = text[0].split(",")
  ranges = [str.split("-") for str in ranges]

  invalid_total = 0

  for nums in ranges:
    for num in range(int(nums[0]), int(nums[1])+1):
      if invalid(num):
        invalid_total += num

  return(invalid_total)

def invalid(num):
    num = str(num)
    nchars = len(num)

    for str_len in range(1, len(num)//2 + 1):
        invalid = True
        if (nchars - str_len) < 0 :
            break

        if (nchars % str_len) != 0:
            continue

        substr_chars = num[:str_len]
        count_to_check = (nchars - str_len) // str_len + 1

        for multi in range(1, count_to_check):
            step = multi * str_len
            if num[step:step+str_len] != substr_chars:
                invalid = False
                break

        if invalid:
            return(True)

    return(False)
Run
aoc_source(day = 2, part = 2)

input = aoc_read(day = 2)

result = aoc_run("solve_day2_part2(input)")
Elapsed: 11.75 seconds
Memory:  20 KB
Back to top