mirror of
https://github.com/cupcakearmy/advent-of-code.git
synced 2024-12-23 00:26:27 +00:00
108 lines
2.7 KiB
Python
108 lines
2.7 KiB
Python
|
#!/usr/bin/env python
|
||
|
|
||
|
from os.path import dirname, join
|
||
|
from typing import Literal, Union
|
||
|
|
||
|
# Day 10
|
||
|
|
||
|
# Common
|
||
|
|
||
|
|
||
|
def read_input(filename):
|
||
|
data = join(dirname(__file__), '..', filename)
|
||
|
with open(data) as f:
|
||
|
return f.read().strip()
|
||
|
|
||
|
|
||
|
test = read_input('test.txt')
|
||
|
data = read_input('input.txt')
|
||
|
|
||
|
Instruction = tuple[int, Union[
|
||
|
tuple[Literal['noop']],
|
||
|
tuple[Literal['addx'], int]
|
||
|
]]
|
||
|
|
||
|
|
||
|
class CRT:
|
||
|
def __init__(self) -> None:
|
||
|
self.clock = 0
|
||
|
self.display = [
|
||
|
['.' for _ in range(40)]
|
||
|
for _ in range(6)
|
||
|
]
|
||
|
|
||
|
def step(self, position: int):
|
||
|
sprite = self.clock % 40
|
||
|
if position - 1 <= sprite and sprite <= position+1:
|
||
|
y = self.clock // 40
|
||
|
x = sprite
|
||
|
self.display[y][x] = "#"
|
||
|
self.clock += 1
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return '\n'.join(map(lambda line: ''.join(line), self.display))
|
||
|
|
||
|
|
||
|
class CPU:
|
||
|
def __init__(self, instructions: list[Instruction]) -> None:
|
||
|
self.instructions = instructions
|
||
|
self.cycle = 1
|
||
|
self.register = 1
|
||
|
self.processing: Instruction = self.instructions.pop(0)
|
||
|
self.crt = CRT()
|
||
|
|
||
|
def step(self) -> bool:
|
||
|
self.cycle += 1
|
||
|
count, instruction = self.processing
|
||
|
if count > 1:
|
||
|
self.processing = (count-1, instruction)
|
||
|
else:
|
||
|
match instruction[0]:
|
||
|
case 'noop':
|
||
|
pass
|
||
|
case 'addx':
|
||
|
self.register += instruction[1]
|
||
|
if len(self.instructions) == 0:
|
||
|
return True
|
||
|
self.processing = self.instructions.pop(0)
|
||
|
return False
|
||
|
|
||
|
def signal_strength(self):
|
||
|
return self.cycle * self.register
|
||
|
|
||
|
def run(self):
|
||
|
signals = 0
|
||
|
while True:
|
||
|
self.crt.step(self.register)
|
||
|
halted = self.step()
|
||
|
if (self.cycle + 20) % 40 == 0:
|
||
|
signals += self.signal_strength()
|
||
|
if halted:
|
||
|
break
|
||
|
return signals
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return f"{self.cycle} X={self.register} {self.processing} SS={self.signal_strength()}\n{self.crt}"
|
||
|
|
||
|
@staticmethod
|
||
|
def parse(data: str):
|
||
|
instructions: list[Instruction] = []
|
||
|
for line in data.splitlines():
|
||
|
command, *args = line.split()
|
||
|
match command:
|
||
|
case 'noop':
|
||
|
instructions.append((1, (command, )))
|
||
|
case 'addx':
|
||
|
instructions.append((2, (command, int(args[0]))))
|
||
|
return CPU(instructions)
|
||
|
|
||
|
|
||
|
# Running
|
||
|
cpu = CPU.parse(test)
|
||
|
print(cpu.run())
|
||
|
print(cpu)
|
||
|
|
||
|
cpu = CPU.parse(data)
|
||
|
print(cpu.run())
|
||
|
print(cpu)
|