You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
113 lines
3.3 KiB
Python
113 lines
3.3 KiB
Python
import re
|
|
|
|
example1 = '1 + 2 * 3 + 4 * 5 + 6'
|
|
example2 = '1 + (2 * 3) + (4 * (5 + 6))'
|
|
example3 = '2 * 3 + (4 * 5)'
|
|
example4 = '5 + (8 * 3 + 9 + 3 * 4 * 3)'
|
|
example5 = '5 * 9 * (7 * 3 * 3 + 9 * 3 + (8 + 6 * 4))'
|
|
example6 = '((2 + 4 * 9) * (6 + 9 * 8 + 6) + 6) + 2 + 4 * 2'
|
|
|
|
with open('input') as f:
|
|
expressions = f.readlines()
|
|
|
|
|
|
def calc(op, a, b):
|
|
if op == '+':
|
|
return a + b
|
|
elif op == '*':
|
|
return a * b
|
|
else:
|
|
raise Exception(f'Operator "{op}" not known')
|
|
|
|
|
|
class Node:
|
|
leaf_value = None
|
|
|
|
def __init__(self, expression):
|
|
# print('Processing', expression)
|
|
while expression[0] == '(':
|
|
level = 0
|
|
split = None
|
|
closing_bracket = None
|
|
for idx, char in enumerate(expression):
|
|
if char == '(':
|
|
level += 1
|
|
elif char == ')':
|
|
level -= 1
|
|
if level == 0 and closing_bracket is None:
|
|
closing_bracket = idx
|
|
|
|
if level == 0 and char == '*' and split is None:
|
|
split = idx
|
|
# print(f'Found split at {i} within {expression}')
|
|
if closing_bracket + 1 == len(expression):
|
|
# print('stipping unneeded parens')
|
|
expression = expression[1:-1]
|
|
else:
|
|
if split is not None:
|
|
# self.split_at(expression, split)
|
|
self.split_at(expression, split)
|
|
else:
|
|
self.split_at(expression, closing_bracket + 2)
|
|
return
|
|
if '(' in expression:
|
|
level = 0
|
|
split = None
|
|
for idx, char in enumerate(expression):
|
|
if char == '(':
|
|
level += 1
|
|
elif char == ')':
|
|
level -= 1
|
|
|
|
if level == 0 and char == '*' and split is None:
|
|
split = idx
|
|
if split is not None:
|
|
self.split_at(expression, split)
|
|
else:
|
|
self.split_at(expression, expression.find('+'))
|
|
elif '*' in expression:
|
|
self.split_at(expression, expression.find('*'))
|
|
elif '+' in expression:
|
|
self.split_at(expression, expression.find('+'))
|
|
else:
|
|
self.leaf_value = int(expression.strip())
|
|
|
|
def split_at(self, expression, idx):
|
|
left = expression[:idx].strip()
|
|
right = expression[idx + 1:].strip()
|
|
op = expression[idx]
|
|
# print(f'Splitting "{left}" "{op}" "{right}"')
|
|
self.left = Node(left)
|
|
self.right = Node(right)
|
|
self.op = op
|
|
|
|
@ property
|
|
def value(self):
|
|
if self.leaf_value is not None:
|
|
return self.leaf_value
|
|
return calc(self.op, self.left.value, self.right.value)
|
|
|
|
|
|
def solve(line):
|
|
return Node(line.strip()).value
|
|
|
|
|
|
print(example1, '=', solve(example1))
|
|
print(example2, '=', solve(example2))
|
|
print(example3, '=', solve(example3))
|
|
print(example4, '=', solve(example4))
|
|
print(example5, '=', solve(example5))
|
|
print(example6, '=', solve(example6))
|
|
|
|
# should be 16530240
|
|
example7 = '3 + (8 * 2 * 4) * 8 * (2 + (8 * 5 + 3 * 4 + 4)) * (2 * (5 * 6))'
|
|
print(example7, '=', solve(example7), 'should be', '16530240')
|
|
|
|
|
|
print('Solution')
|
|
# for expr in expressions:
|
|
# print(expr.strip(), '=', solve(expr))
|
|
|
|
print(sum(map(solve, expressions)))
|
|
|