My 2024 Attempts
Day 1
Part 1
import os
import pandas as pd
input = pd.read_csv(
"2024", "day_01", "input_day01.txt"), sep=" ", header=None
os.path.join(
)input.columns = ["l1", "l2"]
def part1(input):
= list(input["l1"])
l1
l1.sort()= list(input["l2"])
l2
l2.sort()
= pd.DataFrame({"l1": l1, "l2": l2})
df_lists "diff"] = abs(df_lists["l2"] - df_lists["l1"])
df_lists[
return df_lists["diff"].sum()
print(part1(input))
1258579
1.447 seconds elapsed
Part 2
import os
import pandas as pd
input = pd.read_csv(
"2024", "day_01", "input_day01.txt"), sep=" ", header=None
os.path.join(
)input.columns = ["l1", "l2"]
def part2(input):
= list(input["l1"])
l1 = list(input["l2"])
l2
= []
count_array for value in l1:
* l2.count(value))
count_array.append(value
return sum(count_array)
print(part2(input))
23981443
0.025 seconds elapsed
Day 2
Part 1
import os
input = open(os.path.join("2024", "day_02", "input_day02.txt")).read().split("\n")
input = [[int(level) for level in report.split(" ")] for report in input]
def check_if_save(report):
= [report[i + 1] - report[i] for i in range(len(report) - 1)]
increasing if set(increasing) <= {1, 2, 3} or set(increasing) <= {-1, -2, -3}:
return True
else:
return False
def part1(input):
= sum([check_if_save(report) for report in input])
n_safe return n_safe
print(part1(input))
213
0.015 seconds elapsed
Part 2
import os
input = open(os.path.join("2024", "day_02", "input_day02.txt")).read().split("\n")
input = [[int(level) for level in report.split(" ")] for report in input]
def check_if_save(report):
= [report[i + 1] - report[i] for i in range(len(report) - 1)]
increasing if set(increasing) <= {1, 2, 3} or set(increasing) <= {-1, -2, -3}:
return True
else:
return False
def part2(input):
= sum(
n_safe
[any(
[+ report[i + 1 :])
check_if_save(report[:i] for i in range(len(report))
]
)for report in input
]
)return n_safe
print(part2(input))
285
0.032 seconds elapsed
Day 3
Part 1
import os
import re
import math
input = open(os.path.join("2024", "day_03", "input_day03.txt")).read()
def get_multiplications(input):
= re.findall(r"mul\(\d+,\d+\)", input)
mul_strings = [[int(s) for s in re.findall(r"\d+", mul)] for mul in mul_strings]
mul_vals = [math.prod(x) for x in mul_vals]
mults = sum(mults)
mult_sum return mult_sum
def part1(input):
= get_multiplications(input)
mult_sum return mult_sum
print(part1(input))
167090022
0.011 seconds elapsed
Part 2
import os
import re
import math
input = open(os.path.join("2024", "day_03", "input_day03.txt")).read()
def get_multiplications(input):
= re.findall(r"mul\(\d+,\d+\)", input)
mul_strings = [[int(s) for s in re.findall(r"\d+", mul)] for mul in mul_strings]
mul_vals = [math.prod(x) for x in mul_vals]
mults = sum(mults)
mult_sum return mult_sum
def part2(input):
= " ".join(sec.split("don't()")[0] for sec in input.split("do()"))
input_cleaned = get_multiplications(input_cleaned)
mult_sum return mult_sum
print(part2(input))
89823704
0.009 seconds elapsed
Day 4
Part 1
import os
import re
input = open(os.path.join("2024", "day_04", "input_day04.txt")).read()
input = input.split("\n")
def match(matrix, pattern, width):
= 0
matches for i in range(len(matrix) - width + 1):
for j in range(len(matrix[i]) - width + 1):
= "".join(matrix[i + x][j : j + width] for x in range(width))
block += bool(re.match(pattern, block))
matches
return matches
def part1(input):
= 0
word_n for rotation in range(4):
+= sum(row.count("XMAS") for row in input)
word_n += match(input, r"X.{4}M.{4}A.{4}S", 4)
word_n
input = ["".join(row[::-1]) for row in zip(*input)]
return word_n
print(part1(input))
2591
0.139 seconds elapsed
Part 2
import os
import re
input = open(os.path.join("2024", "day_04", "input_day04.txt")).read()
input = input.split("\n")
def match(matrix, pattern, width):
= 0
matches for i in range(len(matrix) - width + 1):
for j in range(len(matrix[i]) - width + 1):
= "".join(matrix[i + x][j : j + width] for x in range(width))
block += bool(re.match(pattern, block))
matches
return matches
def part2(input):
= 0
word_n for rotation in range(4):
+= match(input, r"M.M.A.S.S", 3)
word_n
input = ["".join(row[::-1]) for row in zip(*input)]
return word_n
print(part2(input))
1880
0.132 seconds elapsed
Day 5
Day 6
Day 7
Part 1
import os
import re
from functools import reduce
from itertools import product
from operator import add, mul
input = open(os.path.join("2024", "day_07", "input_day07.txt")).read()
input = [list(map(int, re.findall(r"(\d+)", x))) for x in input.splitlines()]
def check_equation(equation, operators):
= equation[0], equation[1:]
test_val, nums for ops in product(operators, repeat=(len(nums) - 1)):
if reduce(lambda k, x: x[0](k, x[1]), zip(ops, nums[1:]), nums[0]) == test_val:
return True
return False
def part1(input):
= sum(eq[0] for eq in input if check_equation(eq, (add, mul)))
cal_result return cal_result
print(part1(input))
7885693428401
0.402 seconds elapsed
Part 2
import os
import re
from functools import reduce
from itertools import product
from operator import add, mul
input = open(os.path.join("2024", "day_07", "input_day07.txt")).read()
input = [list(map(int, re.findall(r"(\d+)", x))) for x in input.splitlines()]
def check_equation(equation, operators):
= equation[0], equation[1:]
test_val, nums for ops in product(operators, repeat=(len(nums) - 1)):
if reduce(lambda k, x: x[0](k, x[1]), zip(ops, nums[1:]), nums[0]) == test_val:
return True
return False
def _concat(a, b):
*= 10 ** len(str(b))
a return a + b
def part2(input):
= sum(eq[0] for eq in input if check_equation(eq, (add, mul, _concat)))
cal_result
return cal_result
print(part2(input))
348360680516005
29.536 seconds elapsed
Day 8
Part 1
import os
input = open(os.path.join("2024", "day_08", "input_day08.txt")).read().splitlines()
input = [list(line) for line in input]
def get_pair_antinodes_pt1(antinodes, n, m, x_i, y_i, x_j, y_j):
= x_j - x_i
dx = y_j - y_i
dy if x_i - dx >= 0 and y_i - dy >= 0 and y_i - dy < m:
- dx, y_i - dy))
antinodes.add((x_i if x_j + dx < n and y_j + dy < m and y_j + dy >= 0:
+ dx, y_j + dy))
antinodes.add((x_j
def part1(input):
= len(input)
n = len(input[0])
m = set()
antinodes
= {}
antenna_locations for i in range(n):
for j in range(m):
if input[i][j] != ".":
= input[i][j]
c = antenna_locations.get(c, []) + [(i, j)]
antenna_locations[c] for freq, antenna in antenna_locations.items():
if len(antenna) < 2:
continue
for i in range(len(antenna) - 1):
for j in range(i + 1, len(antenna)):
= antenna[i]
x_i, y_i = antenna[j]
x_j, y_j
get_pair_antinodes_pt1(antinodes, n, m, x_i, y_i, x_j, y_j)return len(antinodes)
print(part1(input))
308
0.013 seconds elapsed
Part 2
import os
input = open(os.path.join("2024", "day_08", "input_day08.txt")).read().splitlines()
input = [list(line) for line in input]
def get_pair_antinodes_pt2(antinodes, n, m, x_i, y_i, x_j, y_j):
= x_j - x_i
dx = y_j - y_i
dy = 0
multiplier while (
- multiplier * dx >= 0
x_i and y_i - multiplier * dy >= 0
and y_i - multiplier * dy < m
):= antinodes.add((x_i - multiplier * dx, y_i - multiplier * dy))
antinodes_new += 1
multiplier = 0
multiplier while (
+ multiplier * dx < n
x_j and y_j + multiplier * dy < m
and y_j + multiplier * dy >= 0
):= antinodes.add((x_j + multiplier * dx, y_j + multiplier * dy))
antinodes_new += 1
multiplier
return antinodes_new
def part2(input):
= len(input)
n = len(input[0])
m = set()
antinodes
= {}
antenna_locations for i in range(n):
for j in range(m):
if input[i][j] != ".":
= input[i][j]
c = antenna_locations.get(c, []) + [(i, j)]
antenna_locations[c] for freq, antenna in antenna_locations.items():
if len(antenna) < 2:
continue
for i in range(len(antenna) - 1):
for j in range(i + 1, len(antenna)):
= antenna[i]
x_i, y_i = antenna[j]
x_j, y_j
get_pair_antinodes_pt2(antinodes, n, m, x_i, y_i, x_j, y_j)return len(antinodes)
print(part2(input))
1147
0.013 seconds elapsed
Day 9
Day 10
Day 11
Part 1
import os
from functools import cache
input = open(os.path.join("2024", "day_11", "input_day11.txt")).read().split()
@cache
def calculate_state(n):
if n == 0:
return [1]
= str(n)
string_num if len(string_num) % 2 == 0:
= len(string_num) // 2
mid return [int(string_num[:mid]), int(string_num[mid:])]
= [n * 2024]
new_state return new_state
@cache
def stone_count(stone, blinks_left):
if blinks_left == 0:
return 1
= calculate_state(stone)
new_stone_state = sum(stone_count(num, blinks_left - 1) for num in new_stone_state)
new_stone_count
return new_stone_count
def part1(input):
= 25
n_blinks = 0
total_stones = list(int(stone) for stone in input)
stones for stone in stones:
+= stone_count(stone, n_blinks)
total_stones return total_stones
print(part1(input))
189547
0.017 seconds elapsed
Part 2
import os
from functools import cache
input = open(os.path.join("2024", "day_11", "input_day11.txt")).read().split()
@cache
def calculate_state(n):
if n == 0:
return [1]
= str(n)
string_num if len(string_num) % 2 == 0:
= len(string_num) // 2
mid return [int(string_num[:mid]), int(string_num[mid:])]
= [n * 2024]
new_state return new_state
@cache
def stone_count(stone, blinks_left):
if blinks_left == 0:
return 1
= calculate_state(stone)
new_stone_state = sum(stone_count(num, blinks_left - 1) for num in new_stone_state)
new_stone_count
return new_stone_count
def part2(input):
= 75
n_blinks = list(int(stone) for stone in input)
stones
= 0
total_stones for stone in stones:
+= stone_count(stone, n_blinks)
total_stones
return total_stones
print(part2(input))
224577979481346
0.305 seconds elapsed
Day 12
Day 13
Day 14
Part 1
library(tidyverse)
<- read_delim(
input ::here("2024", "day_14", "input_day14.txt"),
heredelim = " ",
col_names = c("pos", "vel")
)
<- input |>
input mutate(
starts = str_extract_all(pos, "\\d+"),
velocities = str_extract_all(vel, "-?\\d+")
)
<- input |>
starts pull(starts) |>
map(as.numeric)
<- input |>
velocities pull(velocities) |>
map(as.numeric)
<- c(101, 103)
dims
<- function(starts, velocities, dims, times) {
safety_factor <- map2(
end_pos
starts,
velocities,+ y * times) %% dims,
\(x, y, dims, times) (x dims = dims,
times = times
)do.call(rbind, end_pos) |>
as_tibble(.name_repair = "unique") |>
rename(x = "...1", y = "...2")
}
safety_factor(starts, velocities, dims, times = 100) |>
mutate(
quadrant = case_when(
< (dims[1] - 1) / 2 & y < (dims[2] - 1) / 2 ~ 1,
x < (dims[1] - 1) / 2 & y > (dims[2] - 1) / 2 ~ 2,
x > (dims[1] - 1) / 2 & y < (dims[2] - 1) / 2 ~ 3,
x > (dims[1] - 1) / 2 & y > (dims[2] - 1) / 2 ~ 4,
x
)|>
) filter(!is.na(quadrant)) |>
count(quadrant) |>
pull(n) |>
prod() |>
print()
[1] 215987200
0.441 sec elapsed
Part 2
library(tidyverse)
<- read_delim(
input ::here("2024", "day_14", "input_day14.txt"),
heredelim = " ",
col_names = c("pos", "vel")
)
<- input |>
input mutate(
starts = str_extract_all(pos, "\\d+"),
velocities = str_extract_all(vel, "-?\\d+")
)
<- input |>
starts pull(starts) |>
map(as.numeric)
<- input |>
velocities pull(velocities) |>
map(as.numeric)
<- c(101, 103)
dims
<- seq(8000, 8100)
second_range
<- map(
safety_factors
second_range,~ safety_factor(starts, velocities, dims, times = .x) |>
mutate(
second = .x,
quadrant = case_when(
< (dims[1] - 1) / 2 & y < (dims[2] - 1) / 2 ~ 1,
x < (dims[1] - 1) / 2 & y > (dims[2] - 1) / 2 ~ 2,
x > (dims[1] - 1) / 2 & y < (dims[2] - 1) / 2 ~ 3,
x > (dims[1] - 1) / 2 & y > (dims[2] - 1) / 2 ~ 4,
x
)
)|>
) bind_rows()
<- safety_factors |>
min_iterations group_by(second) |>
summarise(
var_x = var(x),
var_y = var(y)
|>
) arrange(var_x, var_y) |>
slice_head(n = 1) |>
pull(second)
print(min_iterations)
|>
safety_factors filter(second == min_iterations) |>
ggplot(aes(x = x, y = y)) +
geom_tile(fill = "white", color = "grey80", size = 0.1) +
scale_y_reverse() +
coord_equal() +
theme_void() +
theme(
plot.margin = margin(rep(2, 4), unit = "mm"),
plot.background = element_rect(
fill = "#0f0f23",
color = "transparent"
)
)
ggsave(
::here("2024", "day_14", "plot_day14_pt2.png"),
herelast_plot(),
height = 5, width = 10, dpi = 300, bg = "transparent"
)
[1] 8050
4.488 sec elapsed
Day 15
Part 1
import os
input = open(os.path.join("2024", "day_15", "input_day15.txt")).read().split("\n\n")
def move_coordinates(coord1, coord2):
= tuple(i + j for i, j in zip(coord1, coord2))
new_coords return new_coords
def part1(input):
= input[0].splitlines()
grid = input[1].replace("\n", "")
moves
= {
boxes
(i, j)for i, line in enumerate(grid)
for j, char in enumerate(line)
if char == "O"
}= {
walls
(i, j)for i, line in enumerate(grid)
for j, char in enumerate(line)
if char == "#"
}= [
robot
(i, j)for i, line in enumerate(grid)
for j, char in enumerate(line)
if char == "@"
]assert len(robot) == 1
= robot[0]
robot
= {"<": (0, -1), "^": (-1, 0), "v": (1, 0), ">": (0, 1)}
move_dict
for move in moves:
= move_dict[move]
direction = move_coordinates(robot, direction)
target1 if target1 not in walls and target1 not in boxes:
= target1
robot else:
= target1
target2 while target2 in boxes:
= move_coordinates(target2, direction)
target2 if target2 in walls:
continue
else:
= target1
robot
boxes.remove(target1)
boxes.add(target2)
= sum(100 * i + j for i, j in boxes)
answer
return answer
print(part1(input))
1415498
0.046 seconds elapsed