diff --git a/2022/day11_monkeys.py b/2022/day11_monkeys.py new file mode 100644 index 0000000..14d7c99 --- /dev/null +++ b/2022/day11_monkeys.py @@ -0,0 +1,142 @@ +from __future__ import annotations + +import dataclasses + + +def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): + print(f"\n+ Running on {filename}") + with open(filename) as f: + data = f.read().strip().split("\n\n") + + data = parse_data(data) + solution_part_1 = solve_part_1(data) + + print(f"1. Found {solution_part_1}") + if expected_part_1: + assert expected_part_1 == solution_part_1 + + solution_part_2 = solve_part_2(data) + print(f"2. Found {solution_part_2}") + if expected_part_2: + assert expected_part_2 == solution_part_2 + + +@dataclasses.dataclass +class Operation: + multiplier: int = 1 + adder: int = 0 + square: bool = False + + def compute(self, value: int) -> int: + if self.square: + value = value * value + else: + value = value * self.multiplier + self.adder + + return int(value / 3) + + +@dataclasses.dataclass +class Monkey: + game: Game + items: list[int] + divisible_by: int + true_monkey: int + false_monkey: int + operation: Operation + inspected_items: int = 0 + + @classmethod + def from_input(cls, text: str, game: Game) -> Monkey: + monkey_description = text.split("\n") + items = [] + operation = None + divisible_by = 1 + true_monkey = 0 + false_monkey = 0 + for line in monkey_description[1:]: + match line.strip().split(": "): + case ["Starting items", text_items]: + items = [int(item) for item in text_items.split(", ")] + case ["Operation", text_operation]: + match text_operation.split(): + case ["new", "=", "old", "*", "old"]: + operation = Operation(square=True) + case ["new", "=", "old", "*", multiplier]: + operation = Operation(multiplier=int(multiplier)) + case ["new", "=", "old", "+", adder]: + operation = Operation(adder=int(adder)) + case ["Test", text_test]: + divisible_by = int(text_test.replace("divisible by", "").strip()) + case ["If true", text_target]: + true_monkey = int( + text_target.replace("throw to monkey", "").strip() + ) + case ["If false", text_target]: + false_monkey = int( + text_target.replace("throw to monkey", "").strip() + ) + monkey = Monkey(game, items, divisible_by, true_monkey, false_monkey, operation) + game.monkeys.append(monkey) + return monkey + + def play_round(self) -> None: + self.inspected_items += len(self.items) + for item in self.items: + new_value = self.operation.compute(item) + if new_value % self.divisible_by == 0: + self.throw(self.true_monkey, new_value) + else: + self.throw(self.false_monkey, new_value) + self.items = [] + + def throw(self, target: int, item: int) -> None: + self.game.monkeys[target].items.append(item) + + def print(self) -> None: + print(", ".join(str(item) for item in self.items)) + + +@dataclasses.dataclass +class Game: + monkeys: list[Monkey] = dataclasses.field(default_factory=list) + + def play_round(self) -> None: + for monkey in self.monkeys: + monkey.play_round() + + def get_ranked_monkeys(self) -> list[Monkey]: + return sorted( + self.monkeys, key=lambda monkey: monkey.inspected_items, reverse=True + ) + + def print_monkeys(self) -> None: + for index, monkey in enumerate(self.monkeys): + print(f"Monkey {index}", end=": ") + monkey.print() + + +DataType = Game + + +def parse_data(data: list[str]) -> DataType: + game = Game() + for text in data: + Monkey.from_input(text, game) + return game + + +def solve_part_1(game: DataType) -> int: + for _ in range(1, 21): + game.play_round() + sorted_monkeys = game.get_ranked_monkeys() + return sorted_monkeys[0].inspected_items * sorted_monkeys[1].inspected_items + + +def solve_part_2(data: DataType) -> int: + return 0 + + +if __name__ == "__main__": + main("inputs/day11-test1", expected_part_1=10605) + main("inputs/day11", expected_part_1=95472) diff --git a/2022/inputs/day11 b/2022/inputs/day11 new file mode 100644 index 0000000..0f98d52 --- /dev/null +++ b/2022/inputs/day11 @@ -0,0 +1,55 @@ +Monkey 0: + Starting items: 52, 60, 85, 69, 75, 75 + Operation: new = old * 17 + Test: divisible by 13 + If true: throw to monkey 6 + If false: throw to monkey 7 + +Monkey 1: + Starting items: 96, 82, 61, 99, 82, 84, 85 + Operation: new = old + 8 + Test: divisible by 7 + If true: throw to monkey 0 + If false: throw to monkey 7 + +Monkey 2: + Starting items: 95, 79 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 5 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 88, 50, 82, 65, 77 + Operation: new = old * 19 + Test: divisible by 2 + If true: throw to monkey 4 + If false: throw to monkey 1 + +Monkey 4: + Starting items: 66, 90, 59, 90, 87, 63, 53, 88 + Operation: new = old + 7 + Test: divisible by 5 + If true: throw to monkey 1 + If false: throw to monkey 0 + +Monkey 5: + Starting items: 92, 75, 62 + Operation: new = old * old + Test: divisible by 3 + If true: throw to monkey 3 + If false: throw to monkey 4 + +Monkey 6: + Starting items: 94, 86, 76, 67 + Operation: new = old + 1 + Test: divisible by 11 + If true: throw to monkey 5 + If false: throw to monkey 2 + +Monkey 7: + Starting items: 57 + Operation: new = old + 2 + Test: divisible by 17 + If true: throw to monkey 6 + If false: throw to monkey 2 diff --git a/2022/inputs/day11-test1 b/2022/inputs/day11-test1 new file mode 100644 index 0000000..30e09e5 --- /dev/null +++ b/2022/inputs/day11-test1 @@ -0,0 +1,27 @@ +Monkey 0: + Starting items: 79, 98 + Operation: new = old * 19 + Test: divisible by 23 + If true: throw to monkey 2 + If false: throw to monkey 3 + +Monkey 1: + Starting items: 54, 65, 75, 74 + Operation: new = old + 6 + Test: divisible by 19 + If true: throw to monkey 2 + If false: throw to monkey 0 + +Monkey 2: + Starting items: 79, 60, 97 + Operation: new = old * old + Test: divisible by 13 + If true: throw to monkey 1 + If false: throw to monkey 3 + +Monkey 3: + Starting items: 74 + Operation: new = old + 3 + Test: divisible by 17 + If true: throw to monkey 0 + If false: throw to monkey 1 diff --git a/2022/new_day b/2022/new_day index 33c6d91..e902174 100755 --- a/2022/new_day +++ b/2022/new_day @@ -16,3 +16,4 @@ fi mkdir -p inputs touch inputs/day$1 touch inputs/day$1-test1 +git add "inputs/day$1*" $filename diff --git a/2022/template.py b/2022/template.py index 80b181c..8a40ea2 100644 --- a/2022/template.py +++ b/2022/template.py @@ -1,3 +1,6 @@ +from __future__ import annotations + + def main(filename: str, expected_part_1: int = None, expected_part_2: int = None): print(f"\n+ Running on {filename}") with open(filename) as f: