mirror of
https://github.com/cupcakearmy/advent-of-code.git
synced 2024-12-23 00:26:27 +00:00
106 lines
3.0 KiB
Python
106 lines
3.0 KiB
Python
|
#!/usr/bin/env python
|
||
|
|
||
|
from functools import reduce
|
||
|
from os.path import dirname, join
|
||
|
from typing import Literal
|
||
|
|
||
|
# Day 11
|
||
|
|
||
|
# 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')
|
||
|
|
||
|
Old = Literal['old']
|
||
|
Operator = Literal['+', '*']
|
||
|
Operation = tuple[Operator, Old | int]
|
||
|
|
||
|
|
||
|
class Monkey:
|
||
|
def __init__(self, items: list[int], operation: Operation, test: tuple[int, int, int], chill: bool) -> None:
|
||
|
self.items = items
|
||
|
self.chill = chill
|
||
|
self.inspected: int = 0
|
||
|
|
||
|
self.divisible = test[0]
|
||
|
self.true = test[1]
|
||
|
self.false = test[2]
|
||
|
|
||
|
op, arg = operation
|
||
|
self._old = arg == 'old'
|
||
|
self._add = op == '+'
|
||
|
self._arg = -1 if self._old else int(arg)
|
||
|
|
||
|
def round(self) -> list[tuple[int, int]]:
|
||
|
l: list[tuple[int, int]] = []
|
||
|
for value in self.items:
|
||
|
arg = value if self._old else self._arg
|
||
|
value = value + arg if self._add else value * arg
|
||
|
if self.chill:
|
||
|
value = value // 3
|
||
|
next_monkey = self.true if value % self.divisible == 0 else self.false
|
||
|
l.append((next_monkey, value))
|
||
|
self.inspected += len(self.items)
|
||
|
self.items.clear()
|
||
|
return l
|
||
|
|
||
|
def __repr__(self) -> str:
|
||
|
return f"{self.inspected}"
|
||
|
|
||
|
@staticmethod
|
||
|
def parse(data: str, chill: bool):
|
||
|
lines = data.splitlines()
|
||
|
items = list(map(int, lines[1][18:].split(', ')))
|
||
|
# Operator
|
||
|
op_raw, arg_raw = lines[2][22:].split()
|
||
|
op: Operator = op_raw
|
||
|
arg: Old | int = 'old' if arg_raw == 'old' else int(arg_raw)
|
||
|
operation: Operation = (op, arg)
|
||
|
# Test
|
||
|
divisible = int(lines[3][21:])
|
||
|
true = int(lines[4][29:])
|
||
|
false = int(lines[5][30:])
|
||
|
return Monkey(items, operation, (divisible, true, false), chill)
|
||
|
|
||
|
|
||
|
class Game:
|
||
|
def __init__(self, monkeys: list[Monkey]) -> None:
|
||
|
self.monkeys = monkeys
|
||
|
dividers = [m.divisible for m in monkeys]
|
||
|
self.common = reduce(lambda a, b: a*b, dividers, 1)
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return ", ".join(map(str, self.monkeys))
|
||
|
|
||
|
def round(self):
|
||
|
for monkey in self.monkeys:
|
||
|
thrown = monkey.round()
|
||
|
for monkey, item in thrown:
|
||
|
self.monkeys[monkey].items.append(item % self.common)
|
||
|
|
||
|
def flag(self, rounds: int = 20):
|
||
|
for _ in range(rounds):
|
||
|
self.round()
|
||
|
inspected = [monkey.inspected for monkey in self.monkeys]
|
||
|
inspected = (sorted(inspected)[-2:])
|
||
|
return inspected[0] * inspected[1]
|
||
|
|
||
|
@staticmethod
|
||
|
def parse(data: str, chill: bool = True):
|
||
|
return Game([Monkey.parse(monkey, chill) for monkey in data.split('\n\n')])
|
||
|
|
||
|
|
||
|
# Running
|
||
|
game = Game.parse(data, chill=True)
|
||
|
print(game.flag(20))
|
||
|
|
||
|
game = Game.parse(data, chill=False)
|
||
|
print(game.flag(10_000))
|