-
Notifications
You must be signed in to change notification settings - Fork 4
/
day21.py
104 lines (90 loc) · 2.88 KB
/
day21.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
"""
Day 21: Monkey Math
"""
from fractions import Fraction
from numbers import Number
SAMPLE_INPUT = [
"root: pppw + sjmn",
"dbpl: 5",
"cczh: sllz + lgvd",
"zczc: 2",
"ptdq: humn - dvpt",
"dvpt: 3",
"lfqf: 4",
"humn: 5",
"ljgn: 2",
"sjmn: drzm * dbpl",
"sllz: 4",
"pppw: cczh / lfqf",
"lgvd: ljgn * ptdq",
"drzm: hmdt - zczc",
"hmdt: 32",
]
def _parse(lines):
definitions = {}
for line in lines:
name, definition = line.split(": ", maxsplit=1)
try:
definitions[name] = int(definition)
except ValueError:
definitions[name] = tuple(definition.rstrip().split(maxsplit=2))
return definitions
def part1(lines):
"""
>>> part1(SAMPLE_INPUT)
152
"""
definitions = _parse(lines)
def evaluate(name):
match definitions[name]:
case value if isinstance(value, Number):
return value
case (lhs, "+", rhs):
return evaluate(lhs) + evaluate(rhs)
case (lhs, "-", rhs):
return evaluate(lhs) - evaluate(rhs)
case (lhs, "*", rhs):
return evaluate(lhs) * evaluate(rhs)
case (lhs, "/", rhs):
return evaluate(lhs) // evaluate(rhs)
return evaluate("root")
def part2(lines):
"""
>>> part2(SAMPLE_INPUT)
301
"""
definitions = _parse(lines)
def evaluate(name):
# pylint: disable=too-many-return-statements
if name == "humn":
return Fraction(1), Fraction(0)
match definitions[name]:
case value if isinstance(value, Number):
return Fraction(0), Fraction(value)
case (lhs, "+", rhs):
slope1, intercept1 = evaluate(lhs)
slope2, intercept2 = evaluate(rhs)
return slope1 + slope2, intercept1 + intercept2
case (lhs, "-", rhs):
slope1, intercept1 = evaluate(lhs)
slope2, intercept2 = evaluate(rhs)
return slope1 - slope2, intercept1 - intercept2
case (lhs, "*", rhs):
slope1, intercept1 = evaluate(lhs)
slope2, intercept2 = evaluate(rhs)
if not slope1:
return intercept1 * slope2, intercept1 * intercept2
if not slope2:
return slope1 * intercept2, intercept1 * intercept2
case (lhs, "/", rhs):
slope1, intercept1 = evaluate(lhs)
slope2, intercept2 = evaluate(rhs)
if not slope2:
return slope1 / intercept2, intercept1 / intercept2
lhs, _, rhs = definitions["root"]
slope1, intercept1 = evaluate(lhs)
slope2, intercept2 = evaluate(rhs)
x = (intercept2 - intercept1) / (slope1 - slope2)
assert x.denominator == 1
return int(x)
parts = (part1, part2)