import sys from pprint import pprint from dataclasses import dataclass from functools import reduce from typing import List import operator @dataclass class Monke: operation: str param: str divisible_by: int if_true: int if_false: int inputs = [l.split("\n") for l in sys.stdin.read().split("\n\n")] monkeys: List[Monke] = [] items = [] inspections = [] visited = [] for monkey in inputs: items.append(tuple(int(x) for x in monkey[1][18:].split(", "))) inspections.append(0) visited.append({}) op, param = monkey[2].split()[4:] divisible_by = int(monkey[3].split()[-1]) if_true = int(monkey[4].split()[-1]) if_false = int(monkey[5].split()[-1]) monkeys.append(Monke(op, param, divisible_by, if_true, if_false)) def do_round(): for m, monke in enumerate(monkeys): # print("Monke", m, monke.items) for item in items[m]: inspections[m] += 1 # print(" W :=", item) param = item if monke.param == "old" else int(monke.param) if monke.operation == "*": item *= param # print(" W *", param, "=", item) elif monke.operation == "+": item += param # print(" W +", param, "=", item) else: assert False item //= 3 # print(" W / 3 =", item) divisible = item % monke.divisible_by == 0 # print(" W %", monke.divisible_by, "== 0 =", divisible) target = monke.if_true if divisible else monke.if_false # print(" Thrown to", target) items[target] = (*items[target], item) items[m] = () for i in range(20): do_round() print(reduce(operator.mul, sorted(inspections)[-2:])) # for i in range(20, 10_000): # if i % 100 == 0: print(i) # do_round() print(reduce(operator.mul, sorted(inspections)[-2:]))