Advent of Code 2024-Day 3: Mull It Over
from advent import parse, re
input = "".join(parse(3))
def solve(ignore_commands=False):
enabled = True
sum = 0
for match in re.finditer(r"mul\((\d{1,3}),(\d{1,3})\)|don't\(\)|do\(\)", input):
if match.group() == "do()":
enabled = True
elif match.group() == "don't()":
enabled = False
elif enabled or ignore_commands:
sum += (int(match.group(1)) * int(match.group(2)))
return sum
# ---------------------------------------------------------------------------------------------
assert solve(True) == 174960292
assert solve() == 56275602
Parsing
Today's input comes in multiple lines, but for our purposes, we just want one long string. parse() will give
us a tuple of strings, and we join them together with join() using an empty string as the separator:
Solution
Parts 1 and 2 are similar enough today that we'll solve them both with a single function that
differentiates between the parts with a parameter indicating whether we should ignore the do() and don't() commands.
The key element today is a regular expression. There are three expressions we care about: mul(m,n), do() and don't(),
so we'll create patterns to match those three alternatives, and combine them with a vertical bar |:
To match mul(m,n), where m and n are 1 to 3 numeric digits: mul\((\d{1,3}),(\d{1,3})\) We use subgroups so we can
easily extract m and n later.
To match do(): do\(\)
To match don't(): don't\(\)
Once we have the proper regular expression matching in place, we simply loop over all the matches, and perform the appropriate action:
do()--> setenabledtoTruedon't()--> setenabledtoFalsemul(m,n)--> if eitherenabledorignore_commandsisTrueadd the product ofmandntosum
New Python Concepts
int()join()Match.group()re.finditer()re- Default parameters
def solve(ignore_commands=False)
Conclusion
While custom parsing code may perform better on today's task, the convenience of regular expressions make them a win in my opinion. Python has fantastic support for regular expressions.