Signed-off-by: AKP <tom@tdpain.net>
This commit is contained in:
akp 2022-12-21 17:12:17 +00:00
parent 5f4ec35ccf
commit 4d3b3fd231
No known key found for this signature in database
GPG key ID: AA5726202C8879B7
7 changed files with 194 additions and 12 deletions

View file

@ -4,18 +4,21 @@ import json
from functools import cmp_to_key from functools import cmp_to_key
_Pair = Union[int, List['_Pair']] _Pair = Union[int, List["_Pair"]]
Pair = Tuple[_Pair, _Pair] Pair = Tuple[_Pair, _Pair]
def parse(instr: str) -> List[Pair]: def parse(instr: str) -> List[Pair]:
res = [] res = []
for raw_pair in instr.strip().split("\n\n"): for raw_pair in instr.strip().split("\n\n"):
a, b = raw_pair.splitlines() a, b = raw_pair.splitlines()
res.append(( res.append(
json.loads(a), (
json.loads(b), json.loads(a),
)) json.loads(b),
)
)
return res return res
@ -26,7 +29,7 @@ def is_pair_well_ordered(pair: Pair) -> Optional[bool]:
if type_a == int and type_b == list: if type_a == int and type_b == list:
return is_pair_well_ordered(([a], b)) return is_pair_well_ordered(([a], b))
elif type_a == list and type_b == int: elif type_a == list and type_b == int:
return is_pair_well_ordered((a, [b])) return is_pair_well_ordered((a, [b]))
@ -34,9 +37,9 @@ def is_pair_well_ordered(pair: Pair) -> Optional[bool]:
if a == b: if a == b:
return None return None
return a < b return a < b
elif type_a == list and type_b == list: elif type_a == list and type_b == list:
for x in zip(a, b): for x in zip(a, b):
y = is_pair_well_ordered(x) y = is_pair_well_ordered(x)
if y is not None: if y is not None:
@ -47,7 +50,7 @@ def is_pair_well_ordered(pair: Pair) -> Optional[bool]:
if la == lb: if la == lb:
return None return None
return la < lb return la < lb
raise ValueError(f"impossible combiation of types ({type_a} and {type_b})") raise ValueError(f"impossible combiation of types ({type_a} and {type_b})")
@ -60,7 +63,6 @@ def is_well_ordered(a, b: Any) -> int:
class Challenge(BaseChallenge): class Challenge(BaseChallenge):
@staticmethod @staticmethod
def one(instr: str) -> int: def one(instr: str) -> int:
inp = parse(instr) inp = parse(instr)
@ -79,4 +81,4 @@ class Challenge(BaseChallenge):
inp.sort(key=is_well_ordered, reverse=True) inp.sort(key=is_well_ordered, reverse=True)
return (inp.index([[2]]) + 1) * (inp.index([[6]]) + 1) return (inp.index([[2]]) + 1) * (inp.index([[6]]) + 1)

View file

@ -0,0 +1 @@
# [Day 21: Monkey Math](https://adventofcode.com/2022/day/21)

View file

@ -0,0 +1,15 @@
{
"day": 21,
"dir": "challenges/2022/21-monkeyMath",
"implementations": {
"Python": {
"part.1.avg": 0.004400461912155151,
"part.1.max": 0.018651485443115234,
"part.1.min": 0.003258943557739258,
"part.2.avg": 0.007683101415634155,
"part.2.max": 0.03519558906555176,
"part.2.min": 0.005395650863647461
}
},
"numRuns": 1000
}

View file

@ -0,0 +1,17 @@
{
"inputFile": "input.txt",
"testCases": {
"one": [
{
"input": "root: pppw + sjmn\ndbpl: 5\ncczh: sllz + lgvd\nzczc: 2\nptdq: humn - dvpt\ndvpt: 3\nlfqf: 4\nhumn: 5\nljgn: 2\nsjmn: drzm * dbpl\nsllz: 4\npppw: cczh / lfqf\nlgvd: ljgn * ptdq\ndrzm: hmdt - zczc\nhmdt: 32\n",
"expected": "152"
}
],
"two": [
{
"input": "root: pppw + sjmn\ndbpl: 5\ncczh: sllz + lgvd\nzczc: 2\nptdq: humn - dvpt\ndvpt: 3\nlfqf: 4\nhumn: 5\nljgn: 2\nsjmn: drzm * dbpl\nsllz: 4\npppw: cczh / lfqf\nlgvd: ljgn * ptdq\ndrzm: hmdt - zczc\nhmdt: 32\n",
"expected": "301"
}
]
}
}

View file

@ -0,0 +1,146 @@
from __future__ import annotations
from typing import *
from aocpy import BaseChallenge
from enum import Enum
import re
class Operator(Enum):
ADD = "+"
SUB = "-"
DIV = "/"
MULT = "*"
def inverse(self) -> Operator:
if self.value == self.ADD.value:
return self.SUB
elif self.value == self.SUB.value:
return self.ADD
elif self.value == self.MULT.value:
return self.DIV
else:
return self.MULT
def calc(self, a_val, b_val) -> float:
res = 0
if self.value == self.ADD.value:
res = a_val + b_val
elif self.value == self.SUB.value:
res = a_val - b_val
elif self.value == self.MULT.value:
res = a_val * b_val
elif self.value == self.DIV.value:
res = a_val / b_val
return res
Monkey = Union[int, Tuple[str, Operator, str]]
Monkies = Dict[str, Monkey]
number_re = re.compile(r"([a-z]{4}): (\d+)")
operation_re = re.compile(r"([a-z]{4}): ([a-z]{4}) ([+\-/*]) ([a-z]{4})")
def parse(instr: str) -> Monkies:
res: Dict[str, Monkey] = {}
for line in instr.strip().splitlines():
if x := number_re.match(line):
name, num_str = x.groups()
num = int(num_str)
res[name] = num
elif x := operation_re.match(line):
name, a, op_str, b = x.groups()
res[name] = (a, Operator(op_str), b)
return res
def evaluate_monkey(monkey: Monkey, monkies: Monkies) -> float:
if type(monkey) == int:
return monkey
elif type(monkey) == tuple:
(a_name, op, b_name) = monkey
a_val = evaluate_monkey(monkies[a_name], monkies)
b_val = evaluate_monkey(monkies[b_name], monkies)
return op.calc(a_val, b_val)
raise ValueError(f"impossible type {type(monkey)}")
def does_branch_contain(target: str, monkey: Monkey, monkies: Monkies) -> bool:
if type(monkey) == int:
return False
elif type(monkey) == tuple:
(a_name, _, b_name) = monkey
if a_name == target or b_name == target:
return True
if does_branch_contain(target, monkies[a_name], monkies):
return True
return does_branch_contain(target, monkies[b_name], monkies)
raise ValueError(f"impossible type {type(monkey)}")
class Challenge(BaseChallenge):
@staticmethod
def one(instr: str) -> int:
inp = parse(instr)
return int(evaluate_monkey(inp["root"], inp))
@staticmethod
def two(instr: str) -> int:
inp = parse(instr)
root = inp["root"]
assert type(root) == tuple
(a_name, _, b_name) = root
if does_branch_contain("humn", inp[a_name], inp):
branch_with_human = inp[a_name]
target_value = evaluate_monkey(inp[b_name], inp)
elif does_branch_contain("humn", inp[b_name], inp):
branch_with_human = inp[b_name]
target_value = evaluate_monkey(inp[a_name], inp)
else:
raise ValueError("neither root branch contains humn")
acc = target_value
cursor = branch_with_human
while True:
(a_name, op, b_name) = cursor
if a_name == "humn" or does_branch_contain("humn", inp[a_name], inp):
x = evaluate_monkey(inp[b_name], inp)
is_first_arg = False
cursor = inp[a_name]
elif b_name == "humn" or does_branch_contain("humn", inp[b_name], inp):
x = evaluate_monkey(inp[a_name], inp)
is_first_arg = True
cursor = inp[b_name]
else:
raise ValueError("neither branch contains humn")
if op == Operator.ADD or op == Operator.MULT:
acc = op.inverse().calc(acc, x)
elif op == Operator.SUB:
if is_first_arg:
acc = op.calc(-acc, -x)
else:
acc = op.inverse().calc(acc, x)
elif op == Operator.DIV:
if is_first_arg:
acc = op.calc(1 / acc, 1 / x)
else:
acc = op.inverse().calc(acc, x)
else:
raise ValueError(f"invalid operator {op}")
if a_name == "humn" or b_name == "humn":
break
return int(acc)

View file

@ -35,4 +35,5 @@ The red dotted line denotes 15 seconds.
| 17 - Pyroclastic Flow | ★ ★ | [Python](17-pyroclasticFlow/py/__init__.py) | Detecting cycles in a large amount of knock-off Tetris. | | 17 - Pyroclastic Flow | ★ ★ | [Python](17-pyroclasticFlow/py/__init__.py) | Detecting cycles in a large amount of knock-off Tetris. |
| 18 - Boiling Boulders | ★ ★ | [Python](18-boilingBoulders/py/__init__.py) | Finding the surface area of a shape specified by a list of unit cubes. | | 18 - Boiling Boulders | ★ ★ | [Python](18-boilingBoulders/py/__init__.py) | Finding the surface area of a shape specified by a list of unit cubes. |
| 19 - Not Enough Minerals | ★ ★ | [Python](19-notEnoughMinerals/py/__init__.py) | Finding the most effective sequence of operations to complete a specific task. | | 19 - Not Enough Minerals | ★ ★ | [Python](19-notEnoughMinerals/py/__init__.py) | Finding the most effective sequence of operations to complete a specific task. |
| 20 - Grove Positioning System | ★ ★ | [Python](20-grovePositioningSystem/py/__init__.py) | My hell is lined with circular sequences. | | 20 - Grove Positioning System | ★ ★ | [Python](20-grovePositioningSystem/py/__init__.py) | My hell is lined with circular sequences. |
| 21 - Monkey Math | ★ ★ | [Python](21-monkeyMath/py/__init__.py) | Trees of math with a fairly satisfying solution :D |

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Before After
Before After