2022-21
Signed-off-by: AKP <tom@tdpain.net>
This commit is contained in:
parent
5f4ec35ccf
commit
4d3b3fd231
7 changed files with 194 additions and 12 deletions
|
@ -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)
|
||||||
|
|
1
challenges/2022/21-monkeyMath/README.md
Normal file
1
challenges/2022/21-monkeyMath/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# [Day 21: Monkey Math](https://adventofcode.com/2022/day/21)
|
15
challenges/2022/21-monkeyMath/benchmark.json
Normal file
15
challenges/2022/21-monkeyMath/benchmark.json
Normal 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
|
||||||
|
}
|
17
challenges/2022/21-monkeyMath/info.json
Normal file
17
challenges/2022/21-monkeyMath/info.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
146
challenges/2022/21-monkeyMath/py/__init__.py
Normal file
146
challenges/2022/21-monkeyMath/py/__init__.py
Normal 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)
|
|
@ -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 |
Loading…
Add table
Add a link
Reference in a new issue