mirror of
https://github.com/Crocmagnon/advent-of-code.git
synced 2024-11-21 14:08:11 +01:00
Solve day 11 part 1
This commit is contained in:
parent
aa723d8a6f
commit
635b5b3aed
5 changed files with 228 additions and 0 deletions
142
2022/day11_monkeys.py
Normal file
142
2022/day11_monkeys.py
Normal file
|
@ -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)
|
55
2022/inputs/day11
Normal file
55
2022/inputs/day11
Normal file
|
@ -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
|
27
2022/inputs/day11-test1
Normal file
27
2022/inputs/day11-test1
Normal file
|
@ -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
|
|
@ -16,3 +16,4 @@ fi
|
|||
mkdir -p inputs
|
||||
touch inputs/day$1
|
||||
touch inputs/day$1-test1
|
||||
git add "inputs/day$1*" $filename
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue