|
|
|
|
|
|
|
|
|
|
|
import logging |
|
|
|
|
|
import re |
|
|
|
|
|
|
|
|
|
|
|
from functools import reduce |
|
|
|
|
|
from itertools import pairwise |
|
|
|
|
|
from sys import stdout |
|
|
|
|
|
|
|
|
|
|
|
# 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)) |
|
|
|
|
|
|
|
|
|
|
|
# Adding up the result of each real instruction produces 161 |
|
|
|
|
|
# (2*4 + 5*5 + 11*8 + 8*5). |
|
|
|
|
|
|
|
|
|
|
|
# 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. |
|
|
|
|
|
|
|
|
|
|
|
LOG_FILENAME = "./day03-1.log" |
|
|
|
|
|
INPUT_FILENAME = "./input03.txt" |
|
|
|
|
|
|
|
|
|
|
|
logger = logging.Logger(__name__) |
|
|
|
|
|
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s') |
|
|
|
|
|
sh = logging.StreamHandler(stdout) |
|
|
|
|
|
sh.setLevel(logging.INFO) |
|
|
|
|
|
sh.setFormatter(formatter) |
|
|
|
|
|
fh = logging.FileHandler(LOG_FILENAME, mode="w", encoding="utf-8") |
|
|
|
|
|
fh.setLevel(logging.DEBUG) |
|
|
|
|
|
fh.setFormatter(formatter) |
|
|
|
|
|
logger.addHandler(sh) |
|
|
|
|
|
logger.addHandler(fh) |
|
|
|
|
|
|
|
|
|
|
|
def multiply_pair(s): |
|
|
|
|
|
pair = [int(x) for x in s[4:-1].split(",")] |
|
|
|
|
|
return reduce(lambda x,y: x*y, pair, 1) |
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
|
|
with open(INPUT_FILENAME, "r") as f: |
|
|
|
|
|
line = "".join(f.readlines()) |
|
|
|
|
|
|
|
|
|
|
|
MUL_REGEX = r"((do|don't)\(\)|mul\(\d{1,3},\d{1,3}\))" |
|
|
|
|
|
matches = re.findall(MUL_REGEX, line) |
|
|
|
|
|
ops = [x[0] for x in matches] |
|
|
|
|
|
logger.info(ops[:25]) |
|
|
|
|
|
good_ops = [] |
|
|
|
|
|
toggle = True |
|
|
|
|
|
for o in ops: |
|
|
|
|
|
if not toggle and o == "do()": |
|
|
|
|
|
toggle = True |
|
|
|
|
|
continue |
|
|
|
|
|
if toggle: |
|
|
|
|
|
if o == "don't()": |
|
|
|
|
|
toggle = False |
|
|
|
|
|
continue |
|
|
|
|
|
if "mul" in o: |
|
|
|
|
|
good_ops.append(o) |
|
|
|
|
|
|
|
|
|
|
|
total_sum = reduce(lambda x,y: x+y, map(multiply_pair, good_ops)) |
|
|
|
|
|
logger.info(f"Total sum: {total_sum}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
main() |