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
0.928 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.029 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.357 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.093 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.067 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.885 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