How to solve Advent of Code 2024 - Day 1 with Python

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):

Advent of Code 2024 - Info Post
Itโ€™s the most festive time of the year - Advent of Code! The highlight of every coderโ€™s December ๐ŸŽ„โ„๏ธ๐Ÿ’ป๐ŸŽ‰ Hereโ€™s everything about my participation, I will link to this from every daysโ€™ post. What even IS Advent of Code??!! Good question, my friend. Here is this yearโ€™s about page: https:

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. ๐Ÿซฃ