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):
🎄❄️💻
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
- if you are also using python, the only "trick" here is knowing that the
- 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. 🪄