Advertisement
Guest User

AoC 2021 - Day 24

a guest
Dec 28th, 2021
1,054
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.89 KB | None | 0 0
  1. """
  2. Advent of Code 2021 - Day 24
  3. https://adventofcode.com/2021/day/24
  4. """
  5.  
  6. from typing import List, Tuple
  7.  
  8. DAY = '24'
  9.  
  10. FULL_INPUT_FILE = f'../inputs/day{DAY}/input.full.txt'
  11. TEST1_INPUT_FILE = f'../inputs/day{DAY}/input.test1.txt'
  12. TEST2_INPUT_FILE = f'../inputs/day{DAY}/input.test2.txt'
  13. TEST3_INPUT_FILE = f'../inputs/day{DAY}/input.test3.txt'
  14.  
  15.  
  16. class ArithmeticLogicUnitRegister:
  17.     def __set_name__(self, owner: object, name: str):
  18.         self.name = name
  19.  
  20.     def __get__(self, obj: object, objtype=None) -> int:
  21.         return getattr(obj, '_registers')[self.name]
  22.  
  23.     def __set__(self, obj: object, value: int):
  24.         getattr(obj, '_registers')[self.name] = value
  25.  
  26.  
  27. class ArithmeticLogicUnit:
  28.     w = ArithmeticLogicUnitRegister()
  29.     x = ArithmeticLogicUnitRegister()
  30.     y = ArithmeticLogicUnitRegister()
  31.     z = ArithmeticLogicUnitRegister()
  32.  
  33.     def __init__(self, w: int = 0, x: int = 0, y: int = 0, z: int = 0) -> None:
  34.         self._registers = {'w': w, 'x': x, 'y': y, 'z': z}
  35.  
  36.     def execute(self, instructions: List[str], inputs: List[int] = None) -> None:
  37.         inputs = inputs.copy() if inputs else []
  38.         operations = {
  39.             'inp': lambda a, b: int(inputs.pop(0)),
  40.             'add': lambda a, b: self._registers[a] + b,
  41.             'mul': lambda a, b: self._registers[a] * b,
  42.             'div': lambda a, b: int(self._registers[a] / b),
  43.             'mod': lambda a, b: self._registers[a] % b,
  44.             'eql': lambda a, b: int(self._registers[a] == b)
  45.         }
  46.         for instruction in instructions:
  47.             operation, arg_a, arg_b = (instruction + ' 0').split(' ')[:3]
  48.             arg_b = self._registers[arg_b] if arg_b.isalpha() else int(arg_b)
  49.             self._registers[arg_a] = (operations[operation])(arg_a, arg_b)
  50.  
  51.  
  52. def check_version_number(instructions: List[str], version_number: int) -> bool:
  53.     alu = ArithmeticLogicUnit()
  54.     alu.execute(instructions, [int(d) for d in list(str(version_number))])
  55.     return not alu.z
  56.  
  57.  
  58. def find_digits(left: int, right: int, find_max: bool = True) -> Tuple[int, int]:
  59.     if find_max:
  60.         if left + right <= 0:
  61.             return 9, 9 + left + right
  62.         else:
  63.             return 9 - left - right, 9
  64.     else:
  65.         if left + right <= 0:
  66.             return 1 - left - right, 1
  67.         else:
  68.             return 1, 1 + left + right
  69.  
  70.  
  71. def calculate_version(instructions: List[str], find_max: bool = True) -> int:
  72.     instruction_sets = []
  73.     for instruction in instructions:
  74.         if instruction.startswith('inp'):
  75.             instruction_sets.append([])
  76.         instruction_sets[-1].append(instruction)
  77.  
  78.     version_number_digits: List = [None] * len(instruction_sets)
  79.     left_digit_stack = []
  80.     for i in range(len(instruction_sets)):
  81.         if instruction_sets[i][4] == 'div z 1':
  82.             left_digit_stack.append((i, instruction_sets[i]))
  83.         else:
  84.             left_i, left_instruction_set = left_digit_stack.pop()
  85.             left_increment = int(left_instruction_set[15].split(' ')[2])
  86.             right_increment = int(instruction_sets[i][5].split(' ')[2])
  87.             version_number_digits[left_i], version_number_digits[i] = \
  88.                 find_digits(left_increment, right_increment, find_max)
  89.     return int(''.join([str(d) for d in version_number_digits]))
  90.  
  91.  
  92. def load_data(infile_path: str) -> List[str]:
  93.     with open(infile_path, 'r', encoding='ascii') as infile:
  94.         return [line.strip() for line in infile.readlines()]
  95.  
  96.  
  97. def part_1(infile_path: str) -> int:
  98.     data = load_data(infile_path)
  99.     return calculate_version(data)
  100.  
  101.  
  102. def part_2(infile_path: str) -> int:
  103.     data = load_data(infile_path)
  104.     return calculate_version(data, False)
  105.  
  106.  
  107. if __name__ == '__main__':
  108.     part1_answer = part_1(FULL_INPUT_FILE)
  109.     print(f'Part 1: {part1_answer}')
  110.  
  111.     part2_answer = part_2(FULL_INPUT_FILE)
  112.     print(f'Part 2: {part2_answer}')
  113.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement