mirror of
https://github.com/cupcakearmy/advent-of-code.git
synced 2024-12-21 15:46:28 +00:00
day 11
This commit is contained in:
parent
fd631127fb
commit
fff2267f21
28
2022/11/README.md
Normal file
28
2022/11/README.md
Normal file
@ -0,0 +1,28 @@
|
||||
# 11
|
||||
|
||||
## Part one
|
||||
|
||||
Easy, fun, lets go.
|
||||
|
||||
## Part two
|
||||
|
||||
Performance was the issue. I started moving functions to inline code (reduce readability for less function calls). It did not make a dent.
|
||||
|
||||
Lesson learned: In python functions calls and destructuring are not expensive.
|
||||
|
||||
What helped a bit was:
|
||||
|
||||
- Precalculating if it's a multiplication or addition for each monkey.
|
||||
- And whether to use the old value or a custom one.
|
||||
|
||||
However that was not nearly enough of a speed boost to get me to the performance needed.
|
||||
|
||||
**Enter math**: We are always diving, so what if I could make the numbers smaller somehow? But everyone uses a different divider? Thats when it struck me! Before passing the item to the next monkey, reduce it with modulo by the biggest common denominator of all monkeys (since the divisions will not influence the other decisions of the other monkeys). And it worked! Speed was no issue anymore ⚡️
|
||||
|
||||
<details>
|
||||
<summary>Solutions</summary>
|
||||
<ol>
|
||||
<li>58322</li>
|
||||
<li>13937702909</li>
|
||||
</ol>
|
||||
</details>
|
105
2022/11/python/main.py
Normal file
105
2022/11/python/main.py
Normal file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from functools import reduce
|
||||
from os.path import dirname, join
|
||||
from typing import Literal
|
||||
|
||||
# Day 11
|
||||
|
||||
# Common
|
||||
|
||||
|
||||
def read_input(filename):
|
||||
data = join(dirname(__file__), '..', filename)
|
||||
with open(data) as f:
|
||||
return f.read().strip()
|
||||
|
||||
|
||||
test = read_input('test.txt')
|
||||
data = read_input('input.txt')
|
||||
|
||||
Old = Literal['old']
|
||||
Operator = Literal['+', '*']
|
||||
Operation = tuple[Operator, Old | int]
|
||||
|
||||
|
||||
class Monkey:
|
||||
def __init__(self, items: list[int], operation: Operation, test: tuple[int, int, int], chill: bool) -> None:
|
||||
self.items = items
|
||||
self.chill = chill
|
||||
self.inspected: int = 0
|
||||
|
||||
self.divisible = test[0]
|
||||
self.true = test[1]
|
||||
self.false = test[2]
|
||||
|
||||
op, arg = operation
|
||||
self._old = arg == 'old'
|
||||
self._add = op == '+'
|
||||
self._arg = -1 if self._old else int(arg)
|
||||
|
||||
def round(self) -> list[tuple[int, int]]:
|
||||
l: list[tuple[int, int]] = []
|
||||
for value in self.items:
|
||||
arg = value if self._old else self._arg
|
||||
value = value + arg if self._add else value * arg
|
||||
if self.chill:
|
||||
value = value // 3
|
||||
next_monkey = self.true if value % self.divisible == 0 else self.false
|
||||
l.append((next_monkey, value))
|
||||
self.inspected += len(self.items)
|
||||
self.items.clear()
|
||||
return l
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.inspected}"
|
||||
|
||||
@staticmethod
|
||||
def parse(data: str, chill: bool):
|
||||
lines = data.splitlines()
|
||||
items = list(map(int, lines[1][18:].split(', ')))
|
||||
# Operator
|
||||
op_raw, arg_raw = lines[2][22:].split()
|
||||
op: Operator = op_raw
|
||||
arg: Old | int = 'old' if arg_raw == 'old' else int(arg_raw)
|
||||
operation: Operation = (op, arg)
|
||||
# Test
|
||||
divisible = int(lines[3][21:])
|
||||
true = int(lines[4][29:])
|
||||
false = int(lines[5][30:])
|
||||
return Monkey(items, operation, (divisible, true, false), chill)
|
||||
|
||||
|
||||
class Game:
|
||||
def __init__(self, monkeys: list[Monkey]) -> None:
|
||||
self.monkeys = monkeys
|
||||
dividers = [m.divisible for m in monkeys]
|
||||
self.common = reduce(lambda a, b: a*b, dividers, 1)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return ", ".join(map(str, self.monkeys))
|
||||
|
||||
def round(self):
|
||||
for monkey in self.monkeys:
|
||||
thrown = monkey.round()
|
||||
for monkey, item in thrown:
|
||||
self.monkeys[monkey].items.append(item % self.common)
|
||||
|
||||
def flag(self, rounds: int = 20):
|
||||
for _ in range(rounds):
|
||||
self.round()
|
||||
inspected = [monkey.inspected for monkey in self.monkeys]
|
||||
inspected = (sorted(inspected)[-2:])
|
||||
return inspected[0] * inspected[1]
|
||||
|
||||
@staticmethod
|
||||
def parse(data: str, chill: bool = True):
|
||||
return Game([Monkey.parse(monkey, chill) for monkey in data.split('\n\n')])
|
||||
|
||||
|
||||
# Running
|
||||
game = Game.parse(data, chill=True)
|
||||
print(game.flag(20))
|
||||
|
||||
game = Game.parse(data, chill=False)
|
||||
print(game.flag(10_000))
|
Loading…
Reference in New Issue
Block a user