110 lines
3.0 KiB
Python
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()
|