-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDay18.py
More file actions
193 lines (155 loc) · 6.39 KB
/
Day18.py
File metadata and controls
193 lines (155 loc) · 6.39 KB
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
from __future__ import annotations
import Utility
filePath = 'input/day18/part1.txt'
class Number:
def __init__(self) -> None:
pass
def initializeFromString(self, input: str, parent: Number, isLeftChild: bool):
self.parent = parent
self.isLeftChild = isLeftChild
if(not input.startswith('[')):
self.isRegularValue = True
self.regularValue = int(input)
else:
self.isRegularValue = False
innerSection = input[1:-1]
middleIndex = 0
if innerSection.startswith('['):
index = 0
bracketDepth = 1
while(bracketDepth > 0):
index += 1
if (innerSection[index] == '['):
bracketDepth += 1
if (innerSection[index] == ']'):
bracketDepth -= 1
# validation:
if innerSection[index + 1] != ',':
raise Exception(
'left and right section should be split by ,')
middleIndex = index + 1
else:
middleIndex = innerSection.find(',')
leftSection = innerSection[0:middleIndex]
rightSection = innerSection[middleIndex + 1:]
leftChild = Number().initializeFromString(leftSection, self, True)
rightChild = Number().initializeFromString(rightSection, self, False)
self.children = [leftChild, rightChild]
return self
def initializeFromRegularValue(self, regularValue: int, parent: Number, isLeftChild: bool):
self.isRegularValue = True
self.regularValue = regularValue
self.parent = parent
self.isLeftChild = isLeftChild
return self
def initializeFromAddition(self, leftNumber: Number, rightNumber: Number):
self.isRegularValue = False
self.isLeftChild = None
self.parent = None
leftNumber.parent = self
rightNumber.parent = self
leftNumber.isLeftChild = True
rightNumber.isLeftChild = False
self.children = [leftNumber, rightNumber]
return self
def __repr__(self) -> str:
if(self.isRegularValue):
return self.regularValue.__repr__()
leftChildRepr = self.children[0].__repr__()
rightChildRepr = self.children[1].__repr__()
return '[' + leftChildRepr + ',' + rightChildRepr + ']'
def reduce(self):
reduced = True
while reduced:
# print(self)
reduced = self.attemptExplode() or self.attemptSplit()
def attemptExplode(self, depth: int = 0) -> bool:
if self.isRegularValue:
return False
if depth >= 4 and self.children[0].isRegularValue:
# Rules guarantee that right child will also be regular value in case of explosion
self.explodePair()
return True
return (self.children[0].attemptExplode(depth + 1)
or self.children[1].attemptExplode(depth + 1))
def explodePair(self):
# To find left number, go up until we reach a parent of which we are the right
# child, go to the left child and recurse on the right child until we reach a regular value
c = self
while((not c == None) and (c.isLeftChild)):
c = c.parent
if (c != None and c.parent != None):
# If == None, no leftwise number exists to add to.
c = c.parent
c = c.children[0]
while (not c.isRegularValue):
c = c.children[1]
# Found number to add left of exploding pair to
c.regularValue += self.children[0].regularValue
# Now do the same logic to find right adjacent number:
c = self
while((not c == None) and (not c.isLeftChild)):
c = c.parent
if (c != None and c.parent != None):
# If == None, no rightwise number exists to add to.
c = c.parent
c = c.children[1]
while (not c.isRegularValue):
c = c.children[0]
# Found number to add right of exploding pair to
c.regularValue += self.children[1].regularValue
self.isRegularValue = True
self.regularValue = 0
self.children = None
pass
def attemptSplit(self) -> bool:
if self.isRegularValue:
if self.regularValue > 9:
self.split()
return True
return False
return self.children[0].attemptSplit() or self.children[1].attemptSplit()
def split(self):
newLeftValue = self.regularValue // 2
newRightValue = self.regularValue - newLeftValue
self.regularValue = None
self.isRegularValue = False
leftChild = Number().initializeFromRegularValue(newLeftValue, self, True)
rightChild = Number().initializeFromRegularValue(newRightValue, self, False)
self.children = [leftChild, rightChild]
def getMagnitude(self) -> int:
if self.isRegularValue:
return self.regularValue
return 3 * self.children[0].getMagnitude() + 2 * self.children[1].getMagnitude()
def solvePart1():
inputLines = Utility.getLinesFromFile(filePath)
currentSum = Number().initializeFromString(inputLines[0], None, None)
for l in inputLines[1:]:
nextNumber = Number().initializeFromString(l, None, None)
currentSum = Number().initializeFromAddition(currentSum, nextNumber)
currentSum.reduce()
print()
print('Solution to part1:')
print(currentSum)
print(currentSum.getMagnitude())
def solvePart2():
inputLines = Utility.getLinesFromFile(filePath)
highestMagnitude = 0
bestReducedSum = None
for i in range(len(inputLines)):
for j in range(len(inputLines)):
if (i == j):
continue
leftNumber = Number().initializeFromString(inputLines[i], None, None)
rightNumber = Number().initializeFromString(inputLines[j], None, None)
sum = Number().initializeFromAddition(leftNumber, rightNumber)
sum.reduce()
if sum.getMagnitude() > highestMagnitude:
highestMagnitude = sum.getMagnitude()
bestReducedSum = sum
print('Solution to part2:')
print(bestReducedSum)
print(highestMagnitude)
if(__name__ == '__main__'):
solvePart1()
solvePart2()