|  |  | @@ -0,0 +1,77 @@ | 
		
	
		
			
			|  |  |  | 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() |