The third day of Advent of Code was yesterday 12/03/2024! If you’re here for the first time today, don’t forget to read the post about Day 1 and Day 2!

I classified the third problem as easy (part 1) and medium (part 2).

Tips#

  • You can use regular expressions to detect mul and extract numbers.
  • In the second part, you can use a simple state machine to enable or disable multiplications.
  • Remember re.compile and re.findall.

How much Python do you need to know?#

The chapters refer to my book Introduction to Programming with Python.

  • Regular expressions and state machines - Chapter 12

Answer#

You can find the auxiliary.files module listing in Day 1.

import re
from aux.files import read_file_without_blank_lines

TEST_INPUT = (
    "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))"
)
REGEX_NUMBER = r"mul(\((\d+),(\d+)\))"
REGEX_DONT = r"(don't\(\))"
REGEX_DO = r"(do\(\))"

regex = re.compile(REGEX_NUMBER)

regex_part2 = re.compile(rf"({REGEX_DONT}|{REGEX_DO}|({REGEX_NUMBER}))")

print(rf"({REGEX_DONT}|{REGEX_DO}|({REGEX_NUMBER}))")


def calculate_sum_of_multiplications(inputs: list[str]) -> int:
    total = 0
    for input_str in inputs:
        for _, num1, num2 in regex.findall(input_str):
            total += int(num1) * int(num2)
    return total


def calculate_sum_of_multiplications_part2(inputs: list[str]) -> int:
    total = 0
    state = 1  # multiplications active
    for input_str in inputs:
        for found in regex_part2.findall(input_str):
            if found[0].startswith("don't"):
                state = 0  # multiplications disabled
            elif found[0].startswith("do"):
                state = 1  # multiplications active
            elif found[0].startswith("mul"):
                if state:
                    (*_, num1, num2) = found
                    total += int(num1) * int(num2)
    return total


total = calculate_sum_of_multiplications([TEST_INPUT])
print(total)
assert total == 161

PROBLEM_INPUT = read_file_without_blank_lines("03/input.txt").splitlines()
total = calculate_sum_of_multiplications(PROBLEM_INPUT)
print(total)
assert total == 184122457

# Part 2

TEST_INPUT_2 = (
    r"xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"
)
total = calculate_sum_of_multiplications_part2([TEST_INPUT_2])
print(total)
assert total == 48

total = calculate_sum_of_multiplications_part2(PROBLEM_INPUT)
print(total)
assert total == 107862689