From 4abb3174d46f009c5e3562c43956dca3029a188d Mon Sep 17 00:00:00 2001 From: davidoji Date: Sat, 1 Nov 2025 19:29:23 +0100 Subject: [PATCH] Solution to Day 3 --- src/Year_2024/Day_03.py | 101 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/Year_2024/Day_03.py diff --git a/src/Year_2024/Day_03.py b/src/Year_2024/Day_03.py new file mode 100644 index 0000000..e6e7f91 --- /dev/null +++ b/src/Year_2024/Day_03.py @@ -0,0 +1,101 @@ +# --- Day 3: Mull It Over --- + +# "Our computers are having issues, so I have no idea if we have any Chief +# Historians in stock! You're welcome to check the warehouse, though," says the +# mildly flustered shopkeeper at the North Pole Toboggan Rental Shop. The +# Historians head out to take a look. + +# The shopkeeper turns to you. "Any chance you can see why our computers are +# having issues again?" + +# The computer appears to be trying to run a program, but its memory (your +# puzzle input) is corrupted. All of the instructions have been jumbled up! + +# It seems like the goal of the program is just to multiply some numbers. It +# does that with instructions like mul(X,Y), where X and Y are each 1-3 digit +# numbers. For instance, mul(44,46) multiplies 44 by 46 to get a result of 2024. +# Similarly, mul(123,4) would multiply 123 by 4. + +# However, because the program's memory has been corrupted, there are also many +# invalid characters that should be ignored, even if they look like part of a +# mul instruction. Sequences like mul(4*, mul(6,9!, ?(12,34), or mul ( 2 , 4 ) +# do nothing. + +# For example, consider the following section of corrupted memory: + +# xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5)) + +# Only the four highlighted sections are real mul instructions. Adding up the +# result of each instruction produces 161 (2*4 + 5*5 + 11*8 + 8*5). + +# Scan the corrupted memory for uncorrupted mul instructions. What do you get if +# you add up all of the results of the multiplications? + +import re + +with open("P3.txt") as f: + memory = [line for line in f.read().strip().split()] + +def part_1(): + total = 0 + pattern = re.compile(r"mul\((\d{1,3}),(\d{1,3})\)") + for line in memory: + matches = pattern.findall(line) + for match in matches: + a, b = map(int, match) + total += a * b + print(f"The sum of all multiplication results is {total}") + + +# --- Part Two --- + +# As you scan through the corrupted memory, you notice that some of the +# conditional statements are also still intact. If you handle some of the +# uncorrupted conditional statements in the program, you might be able to get +# an even more accurate result. + +# There are two new instructions you'll need to handle: + +# The do() instruction enables future mul instructions. +# The don't() instruction disables future mul instructions. + +# Only the most recent do() or don't() instruction applies. At the beginning of +# the program, mul instructions are enabled. + +# For example: + +# xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5)) + +# This corrupted memory is similar to the example from before, but this time +# the mul(5,5) and mul(11,8) instructions are disabled because there is a +# don't() instruction before them. The other mul instructions function normally, +# including the one at the end that gets re-enabled by a do() instruction. + +# This time, the sum of the results is 48 (2*4 + 8*5). + +# Handle the new instructions; what do you get if you add up all of the results +# of just the enabled multiplications? + +def part_2(): + total = 0 + pattern = re.compile(r"mul\((\d{1,3}),(\d{1,3})\)|(do\(\))|((don't\(\)))") + enabled = True + for line in memory: + tokens = re.split(r"(do\(\)|don't\(\)|mul\(\d{1,3},\d{1,3}\))", line) + for token in tokens: + if token == "do()": + enabled = True + elif token == "don't()": + enabled = False + else: + matches = pattern.findall(token) + for match in matches: + if enabled: + a, b = map(int, match[:2]) + total += a * b + print(f"The sum of all enabled multiplication results is {total}") + + +if __name__ == "__main__": + part_1() + part_2() \ No newline at end of file