Advertisement
kupuguy

Advent of Code 2024 Day 17

Dec 17th, 2024
307
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.09 KB | Source Code | 0 0
  1. from pathlib import Path
  2. from typing import Sequence
  3. from operator import xor
  4. from dataclasses import dataclass
  5.  
  6. TEST = """**REDACTED**"""
  7.  
  8.  
  9. @dataclass
  10. class Machine:
  11.     reg_a: int
  12.     reg_b: int
  13.     reg_c: int
  14.     program: list[int]
  15.  
  16.     def combo(self, operand: int) -> int:
  17.         match operand:
  18.             case 4:
  19.                 return self.reg_a
  20.             case 5:
  21.                 return self.reg_b
  22.             case 6:
  23.                 return self.reg_c
  24.             case 7:
  25.                 raise RuntimeError("Reserved operand")
  26.             case _:
  27.                 return operand
  28.  
  29.     def run(self, reg_a: int, reg_b: int = 0, reg_c: int = 0) -> list[int]:
  30.         self.reg_a = reg_a
  31.         self.reg_b = reg_b
  32.         self.reg_c = reg_c
  33.         return list(self.execute())
  34.  
  35.     def execute(self, pc: int = 0) -> Sequence[int]:
  36.         program = self.program
  37.         while pc < len(program):
  38.             instr, operand = program[pc], program[pc + 1]
  39.             pc += 2
  40.             match instr:
  41.                 case 0:  # adv
  42.                     self.reg_a = self.reg_a // (1 << self.combo(operand))
  43.                 case 1:  # bxl
  44.                     self.reg_b = xor(self.reg_b, operand)
  45.                 case 2:
  46.                     self.reg_b = self.combo(operand) % 8
  47.                 case 3:  # jnz
  48.                     if self.reg_a != 0:
  49.                         pc = operand
  50.                 case 4:
  51.                     self.reg_b = xor(self.reg_b, self.reg_c)
  52.                 case 5:
  53.                     yield self.combo(operand) % 8
  54.                 case 6:
  55.                     self.reg_b = self.reg_a // (1 << self.combo(operand))
  56.                 case 7:
  57.                     self.reg_c = self.reg_a // (1 << self.combo(operand))
  58.  
  59.  
  60. def parse(input: str) -> Machine:
  61.     lines = input.splitlines()
  62.     reg_a = int(lines[0].split(":")[1].strip())
  63.     reg_b = int(lines[1].split(":")[1].strip())
  64.     reg_c = int(lines[2].split(":")[1].strip())
  65.     program = [int(n) for n in lines[4].split(":")[1].strip().split(",")]
  66.     return Machine(reg_a, reg_b, reg_c, program)
  67.  
  68.  
  69. def part1(input: str) -> list[int]:
  70.     device = parse(input)
  71.     print(device)
  72.     return list(device.execute())
  73.  
  74.  
  75. assert part1(TEST) == [4, 6, 3, 5, 6, 3, 5, 2, 1, 0]
  76.  
  77. INPUT = Path("input/day17.txt").read_text()
  78. result1 = part1(INPUT)
  79. print("part 1:", ",".join(str(r) for r in result1))
  80.  
  81.  
  82. def solve(device: Machine, reg_a: int, required: list[int]) -> Sequence[int]:
  83.     reg_a *= 8
  84.     for n in range(8):
  85.         output = device.run(reg_a + n)
  86.         if output == required:
  87.             yield reg_a + n
  88.  
  89.  
  90. def part2(input: str) -> list[int]:
  91.     device = parse(input)
  92.     required = []
  93.  
  94.     reg_a_options = {0}
  95.     for value in reversed(device.program):
  96.         required.insert(0, value)
  97.  
  98.         reg_a_options = {
  99.             a for reg_a in reg_a_options for a in solve(device, reg_a, required)
  100.         }
  101.  
  102.     for a in reg_a_options:
  103.         print(a, device.run(a))
  104.     return min(reg_a_options)
  105.  
  106.  
  107. part2_total = part2(INPUT)
  108. print(f"{part2_total=:,}")  # 37,221,274,271,220
  109.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement