-
Notifications
You must be signed in to change notification settings - Fork 0
/
18.py
108 lines (71 loc) · 1.9 KB
/
18.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
105
106
107
108
from lib import *
input = read_input(2021, 18)
lines = input.splitlines()
parent = lambda n: n >> 1
left = lambda n: n << 1
right = lambda n: n << 1 | 1
def parse(lst):
out = [None] * 64
def fill(l, n):
if not isinstance(l, list):
out[n] = l
else:
fill(l[0], left(n))
fill(l[1], right(n))
fill(lst, 1)
return out
def explode(lst):
def move_up(i, x):
while lst[i] is None:
i = parent(i)
lst[i] += x
for n in range(1 << 4, 1 << 5):
if lst[n] is not None:
continue
l = lst[a := left(n)]
r = lst[b := right(n)]
if l is None and r is None:
continue
lst[a] = None
lst[b] = None
lst[n] = 0
if a - 1 >= 1 << 5:
move_up(a - 1, l)
if b + 1 < 1 << 6:
move_up(b + 1, r)
return True
return False
def split(lst, n=1):
if (x := lst[n]) is None:
return split(lst, left(n)) or split(lst, right(n))
if x < 10:
return False
k = x >> 1
lst[n] = None
lst[left(n)] = k
lst[right(n)] = x - k
return True
def add(a, b):
out = [None, None]
for i in range(6):
out += a[1 << i : 1 << i + 1]
out += b[1 << i : 1 << i + 1]
while explode(out) or split(out):
pass
return out
def magnitude(lst, n=1):
if lst[n] is not None:
return lst[n]
return 3 * magnitude(lst, left(n)) + 2 * magnitude(lst, right(n))
def mk_list(lst, n=1):
if lst[n] is not None:
return lst[n]
return [mk_list(lst, left(n)), mk_list(lst, right(n))]
print(magnitude(reduce(add, (parse(ast.literal_eval(line)) for line in lines))))
out = 0
for a in lines:
for b in lines:
if a == b:
continue
out = max(out, magnitude(add(parse(ast.literal_eval(a)), parse(ast.literal_eval(b)))))
print(out)