My 2023 Attempts

Day 1

Nice exercise in working with strings! The overlapping strings (e.g. “eightwo”) were a nice touch.

Part 1

import pandas as pd
import re

input = pd.read_table("2023/day_01/input_day01.txt", names=["string"])

def day1(input, pt2=False):
    if pt2:
        input["string"] = input["string"].apply(lambda k: _translate(k))

    input["first_num"] = input["string"].apply(lambda k: re.search(r"\d+", k).group())
    input["first_num"] = input["first_num"].str[0]
    input["last_num"] = input["string"].apply(
        lambda k: re.search(r"\d+", k[::-1]).group()
    )
    input["last_num"] = input["last_num"].str[0]
    input["value"] = input["first_num"] + input["last_num"]

    return input["value"].astype(int).sum()


print(day1(input, pt2=False))
55017
3.652 seconds elapsed

Part 2

import pandas as pd
import re

input = pd.read_table("2023/day_01/input_day01.txt", names=["string"])

mapping = {
    "one": "1",
    "two": "2",
    "three": "3",
    "four": "4",
    "five": "5",
    "six": "6",
    "seven": "7",
    "eight": "8",
    "nine": "9",
}


def _translate(s):
    for word in mapping:
        s = s.replace(word, word[0] + mapping[word] + word[~0])
    return s


def day1(input, pt2=False):
    if pt2:
        input["string"] = input["string"].apply(lambda k: _translate(k))

    input["first_num"] = input["string"].apply(lambda k: re.search(r"\d+", k).group())
    input["first_num"] = input["first_num"].str[0]
    input["last_num"] = input["string"].apply(
        lambda k: re.search(r"\d+", k[::-1]).group()
    )
    input["last_num"] = input["last_num"].str[0]
    input["value"] = input["first_num"] + input["last_num"]

    return input["value"].astype(int).sum()


print(day1(input, pt2=True))
53539
0.024 seconds elapsed

Day 2

Perfect exercise for {tidyverse}, not so much for Python or pandas. The parsing was hard, but got some inspiration from David Robinson there.

Part 1

library(tidyverse)

input <- read_delim(here::here("2023", "day_02", "input_day02.txt"),
  delim = ":", col_names = c("game", "result")
)

input_parsed <- input |>
  mutate(
    result = str_trim(result),
    game = parse_number(game),
    cubes = str_extract_all(result, "\\d+ [a-z]+")
  ) |>
  unnest(cubes) |>
  separate(cubes, c("number", "color"), sep = " ", convert = TRUE)

max_number <- tribble(
  ~color, ~max_value,
  "red", 12,
  "green", 13,
  "blue", 14
)

input_parsed |>
  inner_join(max_number, by = "color") |>
  group_by(game) |>
  filter(!any(number > max_value)) |>
  distinct(game) |>
  pull(game) |>
  sum() |>
  print()
[1] 2331
0.346 sec elapsed

Part 2

library(tidyverse)

input <- read_delim(here::here("2023", "day_02", "input_day02.txt"),
  delim = ":", col_names = c("game", "result")
)

input_parsed <- input |>
  mutate(
    result = str_trim(result),
    game = parse_number(game),
    cubes = str_extract_all(result, "\\d+ [a-z]+")
  ) |>
  unnest(cubes) |>
  separate(cubes, c("number", "color"), sep = " ", convert = TRUE)

input_parsed |>
  inner_join(max_number, by = "color") |>
  group_by(game, color) |>
  summarise(number = max(number)) |>
  summarise(power = prod(number)) |>
  pull(power) |>
  sum() |>
  print()
[1] 71585
0.113 sec elapsed

Day 3

Really not good at these grid searches, used the solution by Jared Summers in the hope I could learn

Part 1

import os
import re

input = open(os.path.join("2023", "day_03", "input_day03.txt"), "r").read().splitlines()

def part1(input):
    padding = "." * len(input[0])
    padded = [padding] + input
    parts = []

    for i in range(len(input)):
        for match in re.finditer(r"\d+", input[i]):
            start, end = match.span()
            start, end = max(start - 1, 0), min(end + 1, len(input[i]))
            region = "".join([row[start:end] for row in padded[i : i + 3]])
            if re.search(r"[^.0-9]", region):
                parts.append(int(match.group(0)))

    return sum(parts)


print(part1(input))
538046
0.014 seconds elapsed

Part 2

import os
import re

input = open(os.path.join("2023", "day_03", "input_day03.txt"), "r").read().splitlines()

def part2(input):
    padding = "." * len(input[0])
    padded = [padding] + input
    gear_ratios = []

    for i in range(len(input)):
        for gear in re.finditer(r"\*", input[i]):
            numbers = []
            for row in padded[i : i + 3]:
                for n in re.finditer(r"\d+", row):
                    lower, upper = n.span()
                    if lower - 1 <= gear.start() <= upper:
                        numbers.append(int(n.group(0)))
            if len(numbers) == 2:
                gear_ratios.append(numbers[0] * numbers[1])

    return sum(gear_ratios)


print(part2(input))
81709807
0.016 seconds elapsed

Day 4

Part 1

library(tidyverse)

input <- read_delim(here::here("2023", "day_04", "input_day04.txt"),
  delim = ":",
  col_names = c("card", "numbers")
) |>
  mutate(numbers = str_trim(numbers))

input |>
  separate_wider_delim(
    numbers,
    delim = "|", names = c("winning", "hand")
  ) |>
  mutate(
    across(everything(), str_trim),
    across(everything(), ~ str_extract_all(.x, "\\d+")),
    match = map2(winning, hand, intersect),
    n_match = lengths(match)
  ) |>
  filter(n_match > 0) |>
  summarise(
    points = sum(2^(n_match - 1))
  ) |>
  pull(points) |>
  print()
[1] 27059
0.38 sec elapsed

Part 2

library(tidyverse)

input <- read_delim(here::here("2023", "day_04", "input_day04.txt"),
  delim = ":",
  col_names = c("card", "numbers")
) |>
  mutate(numbers = str_trim(numbers))

data_games <- input |>
  separate_wider_delim(
    numbers,
    delim = "|", names = c("winning", "hand")
  ) |>
  mutate(
    across(everything(), str_trim),
    across(everything(), ~ str_extract_all(.x, "\\d+")),
    card = as.numeric(unlist(card)),
    match = map2(winning, hand, intersect),
    n_match = lengths(match)
  ) |>
  rowwise() |>
  mutate(copies = ifelse(n_match > 0, list(card + seq(n_match)), NA)) |>
  ungroup()


cards <- data_games |> pull(card)
collect_scratchcards <- list()
while (!is.null(cards)) {
  collect_scratchcards <- append(collect_scratchcards, list(cards))
  cards <- data_games$copies[cards] |> unlist()
}

print(unlist(collect_scratchcards) |> length())
[1] 5744979
0.964 sec elapsed

Day 5

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