2022-12-11 - Monkey in the Middle
(original .ipynb)
Day 11 puzzle input is a description of how some monkeys will throw some items around between them depending on some properties I'm not even going to begin to summarise (mine is here). Part 1 involves simulating how the monkeys will behave for 20 "rounds" of this throwing, then finding the two monkeys which handled/"inspected" each item and multiplying these numbers. Part 2 involves doing adjusting part of the calc (there's a point where we divide a "worriedness" number previously, that we now no longer do) and running for 10,000
rounds.
from functools import reduce from math import lcm puzzle_input_str = open("./puzzle_input/day11.txt").read() test_input_str = open("./test_input/day11.txt").read() operations = { "*": lambda x,y: x*y, "+": lambda x,y: x+y, "-": lambda x,y: x-y, "/": lambda x,y: x//y, } def parse_monkey_id(line): return int(line[len("Monkey "):][:-1]) def parse_starting_items(line): return [int(s) for s in line[len(" Starting items: "):].split(", ")] def parse_operation(line): tokens = line[len(" Operation: "):].split(" ") func = operations[tokens[-2]] rhs = tokens[-1] return (func, rhs if not rhs.isnumeric() else int(rhs)) def parse_divisible_by(line): tokens = line.split(" ") return int(tokens[-1]) def parse_targets(lines): true_line, false_line = lines true_monkey = true_line.split(" ")[-1] false_monkey = false_line.split(" ")[-1] return int(true_monkey), int(false_monkey) def parse_monkey(monkey_str): lines = monkey_str.splitlines() monkey_id = parse_monkey_id(lines[0]) starting_items = parse_starting_items(lines[1]) operation = parse_operation(lines[2]) divisible_by = parse_divisible_by(lines[3]) true_target, false_target = parse_targets(lines[4:]) return monkey_id, starting_items, operation, divisible_by, true_target, false_target def get_value(v, old): return v if type(v) == int else old def part_one(input_str, worry_divisor=3, rounds=20): monkeys = [parse_monkey(monkey_str) for monkey_str in input_str.split("\n\n")] monkey_items = [] monkey_operations = [] monkey_divisible_by = [] monkey_targets = [] monkey_inspection = [] for monkey_id, starting_items, operation, divisible_by, true_target, false_target in monkeys: monkey_items.append(starting_items) monkey_operations.append(operation) monkey_divisible_by.append(divisible_by) monkey_targets.append({ True: true_target, False: false_target }) monkey_inspection.append(0) foo = lcm(*monkey_divisible_by) while rounds > 0: for m in range(len(monkeys)): next_items = [] func, rhs = monkey_operations[m] while len(monkey_items[m]) > 0: item = monkey_items[m].pop(0) item = func(item, get_value(rhs, item)) // worry_divisor res = item % monkey_divisible_by[m] == 0 monkey_items[monkey_targets[m][res]].append(item % foo) monkey_inspection[m] += 1 rounds -= 1 return reduce(lambda x,y: x*y, list(sorted(monkey_inspection, reverse=True))[:2]) assert 10605 == part_one(test_input_str) print("part one:", part_one(puzzle_input_str))
part one: 110888
def part_two(input_str): return part_one(input_str, 1, 10_000) assert 2713310158 == part_one(test_input_str, 1, 10_000) print("part two", part_two(puzzle_input_str))
part two 25590400731