advent-of-code/2022/python/day11.py

110 lines
3.0 KiB
Python

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()