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

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

The one where you just do some math and then you're done?! 😦

But before we get right into the 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 7 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:
Advent of Code 2024 - Day 7

Every day I complain that I don't know the historical locations and today is finally my day! 💃 The rope bridge from Advent of Code 2022 Day 9 - which I actually did back in the day and even blogged about it: https://sarahglasmacher.com/how-to-solve-advent-of-code-2022-day-9-with-python/

The bridge is broken again, of course, so we need to help calculate some calibration numbers. I hope they now what they're doing - the ropes last time were kind of weird, to be honest... 🧶


Part 1 & 2

Day 7 gives us a test-value and then a list of integers that should be combined to reach the test-value:

# Example input
190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20

Solution Approach:

  • I created a class for the equation (didn't do any classes yet this year, so I mainly did it for the variety)
  • the main idea is to calculate all possible combination of "add" and "multiply"
    • if you are also using python, the only "trick" here is knowing that the itertools module exists in the Python Standard Library
  • Then calculate all the combinations and check if the answer is correct. No other tricks needed. 🤷‍♀️

Since Part 2 only adds another operator, I'll just show everything in one go. 😊

Key Code Snippets:

Help-functions for getting the operator combinations (spoiler for part 2):

def get_all_operator_combinations(
    nr_of_operators: int, part2: bool = False
) -> list[tuple[str, ...]]:
    if part2:
        return list(product(["add", "multiply", "concatenate"], repeat=nr_of_operators))
    else:
        return list(product(["add", "multiply"], repeat=nr_of_operators - 1))

The equation class:

class Equation:
    def __init__(self, line: str):
        integer_list = read_int_list_from_string(line)
        self.target_number = integer_list[0]
        self.input_numbers = integer_list[1:]

    def __repr__(self):
        return f"Equation(target_number={self.target_number}, input_numbers={self.input_numbers})"

    def check_if_solvable(self, part2: bool = False):
        nr_of_operators = len(self.input_numbers) - 1
        operator_combinations = get_all_operator_combinations(
            nr_of_operators, part2=part2
        )

        for operator_combination in operator_combinations:
            if self.check_operator_combination(operator_combination):
                return True
        return False

    def check_operator_combination(self, operator_combination: tuple[str, ...]):
        total = self.input_numbers[0]
        for i, operator in enumerate(operator_combination):
            if operator == "add":
                total += self.input_numbers[i + 1]
            elif operator == "multiply":
                total *= self.input_numbers[i + 1]
            elif operator == "concatenate":
                total = int(str(total) + str(self.input_numbers[i + 1]))
        return total == self.target_number](<def find_start_position(grid: np.ndarray) -%3E tuple[tuple[int, int], str]:
    for i in range(grid.shape[0]):
        for j in range(grid.shape[1]):
            if grid[i, j] in ["^", "v", "%3C", ">"]:
                return (i, j), grid[i, j]

Full Solution for Part 1:

def solve_part_1(mode: str = "example"):
    file_lines = read_input_file(day=7, mode=mode)
    total_calibration_result = 0
    for line in file_lines:
        equation = Equation(line)
        if equation.check_if_solvable():
            total_calibration_result += equation.target_number
    return total_calibration_result

Full Solution for Part 2 (literally the same, except add "concatenate" as an option):

def solve_part_2(mode: str = "example"):
    file_lines = read_input_file(day=7, mode=mode)
    total_calibration_result = 0
    for line in file_lines:
        equation = Equation(line)
        if equation.check_if_solvable(part2=True):
            total_calibration_result += equation.target_number
    return total_calibration_result

Conclusion

I'm pretty sure that after the difficult puzzle yesterday, the creators wanted to give us a break because I couldn't believe that they let us simply try out all combinations. 🤯

I guess the difficult part is knowing about itertools, which I thankfully did, because I had to calculate a bunch of probabilities in my math degree. If you've never seen this module before, take a look around the documentation, it has some incredibly useful functions. 🪄