Compare commits
4 commits
44dafef243
...
091dc34acd
Author | SHA1 | Date | |
---|---|---|---|
Bruno BELANYI | 091dc34acd | ||
Bruno BELANYI | efb846e460 | ||
Bruno BELANYI | a03da090dc | ||
Bruno BELANYI | 19d6374476 |
93
2022/d11/ex1/ex1.py
Executable file
93
2022/d11/ex1/ex1.py
Executable file
|
@ -0,0 +1,93 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import dataclasses
|
||||
import sys
|
||||
from collections import Counter, deque
|
||||
from typing import Literal, Optional
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Operation:
|
||||
lhs: Optional[int]
|
||||
operator: Literal["+", "*"]
|
||||
rhs: Optional[int]
|
||||
|
||||
def __call__(self, old: int) -> int:
|
||||
lhs = old if self.lhs is None else self.lhs
|
||||
rhs = old if self.rhs is None else self.rhs
|
||||
|
||||
if self.operator == "*":
|
||||
return lhs * rhs
|
||||
if self.operator == "+":
|
||||
return lhs + rhs
|
||||
assert False
|
||||
|
||||
@classmethod
|
||||
def from_input(cls, input: str) -> "Operation":
|
||||
assert input.startswith(" Operation: new = ")
|
||||
lhs, op, rhs = input.split()[-3:]
|
||||
|
||||
assert op in ("+", "*") # Sanity check
|
||||
|
||||
return cls(
|
||||
None if lhs == "old" else int(lhs),
|
||||
op, # type: ignore
|
||||
None if rhs == "old" else int(rhs),
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Monkey:
|
||||
items: deque[int]
|
||||
operation: Operation
|
||||
test_divisor: int
|
||||
transfer: dict[bool, int]
|
||||
|
||||
@classmethod
|
||||
def from_input(cls, input: list[str]) -> "Monkey":
|
||||
# Sanity checks
|
||||
assert input[0].startswith("Monkey ")
|
||||
assert "divisible by" in input[3]
|
||||
assert "true" in input[4]
|
||||
assert "false" in input[5]
|
||||
|
||||
items = deque(
|
||||
int(n) for n in input[1].removeprefix(" Starting items: ").split(",")
|
||||
)
|
||||
operation = Operation.from_input(input[2])
|
||||
divisor = int(input[3].split()[-1])
|
||||
transfer = {
|
||||
True: int(input[4].split()[-1]),
|
||||
False: int(input[5].split()[-1]),
|
||||
}
|
||||
return Monkey(items, operation, divisor, transfer)
|
||||
|
||||
|
||||
def solve(input: list[str]) -> int:
|
||||
def do_round(monkeys: list[Monkey], counts: dict[int, int]) -> None:
|
||||
for i, monkey in enumerate(monkeys):
|
||||
counts[i] += len(monkey.items)
|
||||
while monkey.items:
|
||||
item = monkey.items.popleft()
|
||||
item = monkey.operation(item)
|
||||
item //= 3
|
||||
target = monkey.transfer[(item % monkey.test_divisor) == 0]
|
||||
monkeys[target].items.append(item)
|
||||
|
||||
monkeys = [Monkey.from_input(monkey_spec.splitlines()) for monkey_spec in input]
|
||||
counts: Counter[int] = Counter()
|
||||
|
||||
for _ in range(20):
|
||||
do_round(monkeys, counts)
|
||||
|
||||
((_, a), (_, b)) = counts.most_common(2)
|
||||
return a * b
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read().split("\n\n")
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
55
2022/d11/ex1/input
Normal file
55
2022/d11/ex1/input
Normal file
|
@ -0,0 +1,55 @@
|
|||
Monkey 0:
|
||||
Starting items: 50, 70, 54, 83, 52, 78
|
||||
Operation: new = old * 3
|
||||
Test: divisible by 11
|
||||
If true: throw to monkey 2
|
||||
If false: throw to monkey 7
|
||||
|
||||
Monkey 1:
|
||||
Starting items: 71, 52, 58, 60, 71
|
||||
Operation: new = old * old
|
||||
Test: divisible by 7
|
||||
If true: throw to monkey 0
|
||||
If false: throw to monkey 2
|
||||
|
||||
Monkey 2:
|
||||
Starting items: 66, 56, 56, 94, 60, 86, 73
|
||||
Operation: new = old + 1
|
||||
Test: divisible by 3
|
||||
If true: throw to monkey 7
|
||||
If false: throw to monkey 5
|
||||
|
||||
Monkey 3:
|
||||
Starting items: 83, 99
|
||||
Operation: new = old + 8
|
||||
Test: divisible by 5
|
||||
If true: throw to monkey 6
|
||||
If false: throw to monkey 4
|
||||
|
||||
Monkey 4:
|
||||
Starting items: 98, 98, 79
|
||||
Operation: new = old + 3
|
||||
Test: divisible by 17
|
||||
If true: throw to monkey 1
|
||||
If false: throw to monkey 0
|
||||
|
||||
Monkey 5:
|
||||
Starting items: 76
|
||||
Operation: new = old + 4
|
||||
Test: divisible by 13
|
||||
If true: throw to monkey 6
|
||||
If false: throw to monkey 3
|
||||
|
||||
Monkey 6:
|
||||
Starting items: 52, 51, 84, 54
|
||||
Operation: new = old * 17
|
||||
Test: divisible by 19
|
||||
If true: throw to monkey 4
|
||||
If false: throw to monkey 1
|
||||
|
||||
Monkey 7:
|
||||
Starting items: 82, 86, 91, 79, 94, 92, 59, 94
|
||||
Operation: new = old + 7
|
||||
Test: divisible by 2
|
||||
If true: throw to monkey 5
|
||||
If false: throw to monkey 3
|
98
2022/d11/ex2/ex2.py
Executable file
98
2022/d11/ex2/ex2.py
Executable file
|
@ -0,0 +1,98 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import dataclasses
|
||||
import functools
|
||||
import sys
|
||||
from collections import Counter, deque
|
||||
from typing import Literal, Optional
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Operation:
|
||||
lhs: Optional[int]
|
||||
operator: Literal["+", "*"]
|
||||
rhs: Optional[int]
|
||||
|
||||
def __call__(self, old: int) -> int:
|
||||
lhs = old if self.lhs is None else self.lhs
|
||||
rhs = old if self.rhs is None else self.rhs
|
||||
|
||||
if self.operator == "*":
|
||||
return lhs * rhs
|
||||
if self.operator == "+":
|
||||
return lhs + rhs
|
||||
assert False
|
||||
|
||||
@classmethod
|
||||
def from_input(cls, input: str) -> "Operation":
|
||||
assert input.startswith(" Operation: new = ")
|
||||
lhs, op, rhs = input.split()[-3:]
|
||||
|
||||
assert op in ("+", "*") # Sanity check
|
||||
|
||||
return cls(
|
||||
None if lhs == "old" else int(lhs),
|
||||
op, # type: ignore
|
||||
None if rhs == "old" else int(rhs),
|
||||
)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Monkey:
|
||||
items: deque[int]
|
||||
operation: Operation
|
||||
test_divisor: int
|
||||
transfer: dict[bool, int]
|
||||
|
||||
@classmethod
|
||||
def from_input(cls, input: list[str]) -> "Monkey":
|
||||
# Sanity checks
|
||||
assert input[0].startswith("Monkey ")
|
||||
assert "divisible by" in input[3]
|
||||
assert "true" in input[4]
|
||||
assert "false" in input[5]
|
||||
|
||||
items = deque(
|
||||
int(n) for n in input[1].removeprefix(" Starting items: ").split(",")
|
||||
)
|
||||
operation = Operation.from_input(input[2])
|
||||
divisor = int(input[3].split()[-1])
|
||||
transfer = {
|
||||
True: int(input[4].split()[-1]),
|
||||
False: int(input[5].split()[-1]),
|
||||
}
|
||||
return Monkey(items, operation, divisor, transfer)
|
||||
|
||||
|
||||
def solve(input: list[str]) -> int:
|
||||
def do_round(monkeys: list[Monkey], counts: dict[int, int]) -> None:
|
||||
modulo = functools.reduce(
|
||||
lambda lhs, rhs: lhs * rhs,
|
||||
(monkey.test_divisor for monkey in monkeys),
|
||||
)
|
||||
for i, monkey in enumerate(monkeys):
|
||||
counts[i] += len(monkey.items)
|
||||
while monkey.items:
|
||||
item = monkey.items.popleft()
|
||||
item = monkey.operation(item)
|
||||
item %= modulo # Keep a reasonable range on this value
|
||||
target = monkey.transfer[(item % monkey.test_divisor) == 0]
|
||||
monkeys[target].items.append(item)
|
||||
|
||||
monkeys = [Monkey.from_input(monkey_spec.splitlines()) for monkey_spec in input]
|
||||
counts: Counter[int] = Counter()
|
||||
|
||||
for _ in range(10_000):
|
||||
do_round(monkeys, counts)
|
||||
|
||||
((_, a), (_, b)) = counts.most_common(2)
|
||||
return a * b
|
||||
|
||||
|
||||
def main() -> None:
|
||||
input = sys.stdin.read().split("\n\n")
|
||||
print(solve(input))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
55
2022/d11/ex2/input
Normal file
55
2022/d11/ex2/input
Normal file
|
@ -0,0 +1,55 @@
|
|||
Monkey 0:
|
||||
Starting items: 50, 70, 54, 83, 52, 78
|
||||
Operation: new = old * 3
|
||||
Test: divisible by 11
|
||||
If true: throw to monkey 2
|
||||
If false: throw to monkey 7
|
||||
|
||||
Monkey 1:
|
||||
Starting items: 71, 52, 58, 60, 71
|
||||
Operation: new = old * old
|
||||
Test: divisible by 7
|
||||
If true: throw to monkey 0
|
||||
If false: throw to monkey 2
|
||||
|
||||
Monkey 2:
|
||||
Starting items: 66, 56, 56, 94, 60, 86, 73
|
||||
Operation: new = old + 1
|
||||
Test: divisible by 3
|
||||
If true: throw to monkey 7
|
||||
If false: throw to monkey 5
|
||||
|
||||
Monkey 3:
|
||||
Starting items: 83, 99
|
||||
Operation: new = old + 8
|
||||
Test: divisible by 5
|
||||
If true: throw to monkey 6
|
||||
If false: throw to monkey 4
|
||||
|
||||
Monkey 4:
|
||||
Starting items: 98, 98, 79
|
||||
Operation: new = old + 3
|
||||
Test: divisible by 17
|
||||
If true: throw to monkey 1
|
||||
If false: throw to monkey 0
|
||||
|
||||
Monkey 5:
|
||||
Starting items: 76
|
||||
Operation: new = old + 4
|
||||
Test: divisible by 13
|
||||
If true: throw to monkey 6
|
||||
If false: throw to monkey 3
|
||||
|
||||
Monkey 6:
|
||||
Starting items: 52, 51, 84, 54
|
||||
Operation: new = old * 17
|
||||
Test: divisible by 19
|
||||
If true: throw to monkey 4
|
||||
If false: throw to monkey 1
|
||||
|
||||
Monkey 7:
|
||||
Starting items: 82, 86, 91, 79, 94, 92, 59, 94
|
||||
Operation: new = old + 7
|
||||
Test: divisible by 2
|
||||
If true: throw to monkey 5
|
||||
If false: throw to monkey 3
|
Loading…
Reference in a new issue