import shared import operator import math from dataclasses import dataclass from typing import Callable @dataclass class Monkey: number: int items: list div: int t: int f: int by: int op: operator inspect_count: int = 0 def load_monkeys(lines): monkeys = [] count = 0 for line in lines: if line.lstrip().startswith("Starting"): items = list(map(int, line.split(": ")[-1].split(","))) elif line.lstrip().startswith("Operation"): op = line.split(": ")[-1] try: by = int(line.split(" ")[-1]) except ValueError: by = None # know None means by self if "*" in op: operand = operator.mul elif "+" in op: operand = operator.add elif line.lstrip().startswith("Test"): div = int(line.split(" ")[-1]) elif line.lstrip().startswith("If true"): true = int(line.split(" ")[-1]) elif line.lstrip().startswith("If false"): false = int(line.split(" ")[-1]) monkey = Monkey( number=count, items=items, op=operand, by=by, div=div, t=true, f=false ) monkeys.append(monkey) count += 1 lcm = math.lcm(*[m.div for m in monkeys]) return monkeys, lcm def part1(lines): monkeys, _ = load_monkeys(lines) for current_round in range(20): for monkey in monkeys: for item in monkey.items: monkey.inspect_count += 1 if monkey.by is None: # Self item = monkey.op(item, item) else: item = monkey.op(item, monkey.by) item = item // 3 if item % monkey.div == 0: to = monkey.t else: to = monkey.f monkeys[to].items.append(item) monkey.items = [] counts = list(sorted([monkey.inspect_count for monkey in monkeys])) total = counts[-1] * counts[-2] print(total) def part2(lines): monkeys, lcm = load_monkeys(lines) for current_round in range(10000): for monkey in monkeys: for item in monkey.items: monkey.inspect_count += 1 if monkey.by is None: # Self item = monkey.op(item, item) else: item = monkey.op(item, monkey.by) item = item % lcm if item % monkey.div == 0: to = monkey.t else: to = monkey.f monkeys[to].items.append(item) monkey.items = [] counts = list(sorted([monkey.inspect_count for monkey in monkeys])) total = counts[-1] * counts[-2] print(total) def main(): rows = [row for row in shared.load(11)] part1(rows) part2(rows) if __name__ == "__main__": main()