-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadvent-18.py
179 lines (127 loc) · 4.25 KB
/
advent-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
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
"""
URL for challenge: https://adventofcode.com/2020/day/18
Check PR description for working of solution, notes, etc.
"""
import matplotlib.pyplot as plt
import networkx as nx
from networkx.drawing.nx_agraph import graphviz_layout
import re
import string
class Node():
def __init__(self, value):
self.value = value
self.left_child = None
self.right_child = None
self.parent = None
def process_input():
f = open("advent-18-input.txt")
expressions = []
for line in f.readlines():
line = line.strip().split(' ')
expression = []
for elem in line:
parsed_elem = re.split('([()])', elem)
expression += [pe for pe in parsed_elem if pe]
expressions.append(expression)
return expressions
def part1():
expressions = process_input()
total_sum = 0
for expression in expressions:
tree = create_tree(expression)
total_sum += evaluate_tree(tree)
return total_sum
def part2():
expressions = process_input()
total_sum = 0
for expression in expressions:
tree = create_tree(expression)
rearrange_nodes(tree)
# The root node after rearrangement may be
# different from the one before rearrangement
root_node = get_root_node(tree)
total_sum += evaluate_tree(root_node)
return total_sum
def create_tree(expression):
digits = set(string.digits)
current_node = Node('+')
current_node.left_child = Node(0)
current_node.left_child.parent = current_node
idx = 0
while idx < len(expression):
element = expression[idx]
if set(element).issubset(digits):
node = Node(int(element))
current_node.right_child = node
node.parent = current_node
elif element in ['+', '*']:
node = Node(element)
node.left_child = current_node
current_node.parent = node
current_node = node
elif element == '(':
sub_result = create_tree(expression[idx+1:])
current_node.right_child = sub_result[0]
sub_result[0].parent = current_node
idx += sub_result[1]
else:
return current_node, idx + 1
idx += 1
return current_node
def evaluate_tree(node):
if not node:
return 0
if not node.left_child and not node.right_child:
return node.value
if node.value == '+':
return evaluate_tree(node.left_child) + evaluate_tree(node.right_child)
return evaluate_tree(node.left_child) * evaluate_tree(node.right_child)
def get_root_node(node):
if not node.parent:
return node
return get_root_node(node.parent)
def rearrange_nodes(node):
if not node.left_child and not node.right_child:
return node
rearrange_nodes(node.left_child)
rearrange_nodes(node.right_child)
left_child = node.left_child
if node.value == '+' and left_child.value == '*':
if node.parent:
if node == node.parent.left_child:
node.parent.left_child = left_child
else:
node.parent.right_child = left_child
left_child.parent = node.parent
node.left_child = left_child.right_child
left_child.right_child.parent = node
left_child.right_child = node
node.parent = left_child
return node
def run():
chall = int(input("Please enter either 1 or 2 for the challenges: "))
if chall == 1:
print(part1())
elif chall == 2:
print(part2())
else:
print("You need to enter either 1 or 2")
exit(1)
# (Only one instance of plt.show() is required)
# This will get used when draw_tree() is called
plt.show()
def gather_edges(node):
all_edges = []
if node.left_child:
all_edges.append((node, node.left_child))
all_edges += gather_edges(node.left_child)
if node.right_child:
all_edges.append((node, node.right_child))
all_edges += gather_edges(node.right_child)
return all_edges
def draw_tree(root_node):
tree = nx.Graph(gather_edges(root_node))
plt.figure()
nx.draw(tree, pos=graphviz_layout(tree, prog='dot'),
labels={node: node.value for node in tree}, arrows=False)
run()