101 lines
3.1 KiB
Python
101 lines
3.1 KiB
Python
from collections import defaultdict
|
|
from math import lcm
|
|
from tools.aoc import AOCDay
|
|
from typing import Any
|
|
|
|
|
|
class Monkey:
|
|
def __init__(self, monkey_id: int):
|
|
self.monkey_id = monkey_id
|
|
self.items = []
|
|
self.operation = None
|
|
self.test = None
|
|
self.action_true = None
|
|
self.action_false = None
|
|
|
|
def turn(self, part2: bool = False):
|
|
for _ in range(len(self.items)):
|
|
item = self.items.pop(0)
|
|
op, right = self.operation
|
|
|
|
if op == "+":
|
|
item += int(right)
|
|
elif right == "old":
|
|
item *= item
|
|
else:
|
|
item *= int(right)
|
|
|
|
if not part2:
|
|
item //= 3
|
|
|
|
if item % self.test == 0:
|
|
yield item, self.action_true
|
|
else:
|
|
yield item, self.action_false
|
|
|
|
|
|
class Day(AOCDay):
|
|
inputs = [
|
|
[
|
|
(10605, "input11_test"),
|
|
(98280, "input11"),
|
|
],
|
|
[
|
|
(2713310158, "input11_test"),
|
|
(17673687232, "input11"),
|
|
]
|
|
]
|
|
|
|
def get_monkeys(self) -> list:
|
|
monkeys = {}
|
|
current_monkey = None
|
|
for line in self.getInput():
|
|
if not line:
|
|
continue
|
|
|
|
if line.startswith("Monkey"):
|
|
current_monkey = Monkey(int(line[:-1].split(" ")[1]))
|
|
monkeys[current_monkey.monkey_id] = current_monkey
|
|
elif line.startswith(" Starting items:"):
|
|
current_monkey.items = list(map(int, line.split(": ")[1].split(", ")))
|
|
elif line.startswith(" Operation"):
|
|
current_monkey.operation = line.split(": ")[1].split(" = ")[1].split(" ")[1:]
|
|
elif line.startswith(" Test:"):
|
|
current_monkey.test = int(line.split(" ")[-1])
|
|
elif line.startswith(" If true:"):
|
|
current_monkey.action_true = int(line.split(" ")[-1])
|
|
elif line.startswith(" If false:"):
|
|
current_monkey.action_false = int(line.split(" ")[-1])
|
|
else:
|
|
print("Don't know how to parse '", line, "'")
|
|
|
|
return [monkeys[x] for x in sorted(monkeys)]
|
|
|
|
def get_monkey_business(self, amount: int = 20, part2: bool = False) -> int:
|
|
monkeys = self.get_monkeys()
|
|
monkey_inspects = defaultdict(int)
|
|
modder = lcm(*[m.test for m in monkeys])
|
|
|
|
for _ in range(amount):
|
|
for monkey in monkeys:
|
|
for item, target in monkey.turn(part2):
|
|
monkey_inspects[monkey.monkey_id] += 1
|
|
if part2:
|
|
monkeys[target].items.append(item % modder)
|
|
else:
|
|
monkeys[target].items.append(item)
|
|
|
|
f = sorted(monkey_inspects.values())[-2:]
|
|
return f[0] * f[1]
|
|
|
|
def part1(self) -> Any:
|
|
return self.get_monkey_business(20, False)
|
|
|
|
def part2(self) -> Any:
|
|
return self.get_monkey_business(10_000, True)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
day = Day(2022, 11)
|
|
day.run(verbose=True)
|