How to solve Advent of Code 2024 - Day 1 with Python
It's the most festive time of the year - Advent of Code! The highlight of every coder's December. ๐โ๏ธ๐ป๐ But before we get right into the first day and my solution for this day's puzzle, here is the info on how I approach this whole event (where my code is, what editor I use, etc):
Day 1 Puzzle
On my blog here, I will go through the puzzle and my way of solving it. If you want, you can jump directly to the code solution here: GitHub .py script
Here is the challenge, if you want to read the full puzzle: https://adventofcode.com/2024/day/1
In summary, on Day 1, we learn that the Chief Historian, who is always present for the big Christmas sleigh launch, has gone missing! A group of Elvish Senior Historians needs our help to find him (someone should have just given him a phone...). To start, they decide to check his office, where they discover scattered notes and lists of location IDs instead of names. The Historians split into two groups to compile a complete list, but their lists donโt match. Now, itโs up to us to help reconcile the differences so we can even start the 25 day search... ๐ฎโ๐จ
Part 1
Day 1 gives you an example input text portraying the two lists side by side:
3 4
4 3
2 5
1 3
3 9
3 3
For the solution we want the first and last digit of each line.
To parse the input I always put the text into a .txt
file and read from there. This strategy means I can easily switch between the example
, which is included in the puzzle description and public, including its solution, and the final input
each of us gets (the input should be kept private).
First, I read from this file line by line:
with open(file_path, "r") as f:
lines = f.readlines()
file_lines = [line.strip() for line in lines]
(I also put this in a aoc_utils.py
file and into a function, because we will use something like this again and again and again this year ๐)
This returns: ['3 4', '4 3', '2 5', '1 3', '3 9', '3 3']
.
I then iterate through each line (double_int_str
) with the following function to extract the integers:
def get_int_pair(double_int_str: str) -> tuple[int, int]:
double_int_str = double_int_str.strip()
left_str, right_str = double_int_str.split()
first_int = int(left_str)
last_int = int(right_str)
return first_int, last_int
Some pointers:
- I
strip()
the line to get rid of any trailing whitespace that I might have copy-pasted from the website. - the
.split()
function by defaults splits on whitespace - which is exactly what is between the first and second number in every line - then simply cast the parts by calling
int()
on them (it's called "type casting" if you want to learn more)
Then iterate through the lines and add the integers to a left and right list:
left_list = []
right_list = []
for line in file_lines:
left_int, right_int = get_int_pair(line)
left_list.append(left_int)
right_list.append(right_int)
Before we can compare the entries (and calculate the difference), they want us to sort them. I just use the built-in sorting from Python's list
.
left_list.sort()
right_list.sort()
We can then use list comprehension and the handy zip
function to calculate the absolute differences between the two lists pairwise:
absolute_diff_list = [
abs(left_int - right_int) for left_int, right_int in zip(left_list, right_list)]
sum(absolute_diff_list)
And the end we just sum up over those differences.
Here's the full solution for part 1:
def solve_part_1(mode: str = "input"):
file_lines = read_input_file(day=1, part=1, mode=mode)
left_list = []
right_list = []
for line in file_lines:
left_int, right_int = get_int_pair(line)
left_list.append(left_int)
right_list.append(right_int)
left_list.sort()
right_list.sort()
absolute_diff_list = [
abs(left_int - right_int) for left_int, right_int in zip(left_list, right_list)
]
return sum(absolute_diff_list)
Part 2
Well, turns out the lists are quite different indeed... ๐ We now need to figure out how often each number of the left list appears in the right list.
Then we compute a similarity score for each entry in the left list:
similarity_score = left_value * nr_of_times_this_value_is_in_the_right_list
In code this means:
similarity_scores = []
for left_int in left_list:
number_of_occurrences = right_list.count(left_int)
similarity_scores.append(left_int * number_of_occurrences)
... then sum up the similarity scores.
The full code for part 2 reuses the parts for building this lists (now in their own build_lists
function):
def solve_part_2(mode: str = "example"):
file_lines = read_input_file(day=1, mode=mode)
left_list, right_list = build_lists(file_lines)
similarity_scores = []
for left_int in left_list:
number_of_occurrences = right_list.count(left_int)
similarity_scores.append(left_int * number_of_occurrences)
return sum(similarity_scores)
Conclusion
So far, so good. This has been quite pleasant, but Day 1 usually is - after you figured out how to parse inputs.
I'm trying my best to write clean-ish code and built reusable functions this year. I am nervous for the coming days. ๐ซฃ