|
@@ -0,0 +1,186 @@
|
|
|
+from copy import deepcopy
|
|
|
+from math import floor
|
|
|
+from itertools import product
|
|
|
+from util import get_input
|
|
|
+
|
|
|
+input = get_input("24.input")
|
|
|
+
|
|
|
+# Yes, you have to adjust these manually.
|
|
|
+# Yes, it can be done automatically.
|
|
|
+# No, I don't want to.
|
|
|
+# 1111
|
|
|
+# 01234567890123
|
|
|
+part1 = "93959993429899"
|
|
|
+part2 = "11815671117121"
|
|
|
+
|
|
|
+lookup = {k: int(part2[k]) for k in range(14)}
|
|
|
+
|
|
|
+def paren(exp):
|
|
|
+ return "(" + exp + ")"
|
|
|
+
|
|
|
+def pprint(exp):
|
|
|
+ if exp[0] == 'c':
|
|
|
+ return str(exp[1])
|
|
|
+ elif exp[0] == 'in':
|
|
|
+ return 'in' + str(exp[1])
|
|
|
+ elif exp[0] == 'add':
|
|
|
+ return paren(pprint(exp[1]) + ' + ' + pprint(exp[2]))
|
|
|
+ elif exp[0] == 'mul':
|
|
|
+ return paren(pprint(exp[1]) + ' * ' + pprint(exp[2]))
|
|
|
+ elif exp[0] == 'div':
|
|
|
+ return paren(pprint(exp[1]) + ' / ' + pprint(exp[2]))
|
|
|
+ elif exp[0] == 'mod':
|
|
|
+ return paren(pprint(exp[1]) + ' % ' + pprint(exp[2]))
|
|
|
+ elif exp[0] == 'eql':
|
|
|
+ return paren(pprint(exp[1]) + ' == ' + pprint(exp[2]))
|
|
|
+ elif exp[0] == 'sum':
|
|
|
+ return paren(" + ".join(pprint(t) for t in exp[1]))
|
|
|
+ raise Exception("Not allowed: {}".format(exp[0]))
|
|
|
+
|
|
|
+def evl(exp, lookup):
|
|
|
+ if exp[0] == 'c':
|
|
|
+ return exp[1]
|
|
|
+ elif exp[0] == 'in':
|
|
|
+ return lookup[exp[1]]
|
|
|
+ elif exp[0] == 'add':
|
|
|
+ return evl(exp[1], lookup) + evl(exp[2], lookup)
|
|
|
+ elif exp[0] == 'mul':
|
|
|
+ return evl(exp[1], lookup) * evl(exp[2], lookup)
|
|
|
+ elif exp[0] == 'div':
|
|
|
+ return floor(evl(exp[1], lookup) / evl(exp[2], lookup))
|
|
|
+ elif exp[0] == 'mod':
|
|
|
+ return evl(exp[1], lookup) % evl(exp[2], lookup)
|
|
|
+ elif exp[0] == 'eql':
|
|
|
+ return 1 if evl(exp[1], lookup) == evl(exp[2], lookup) else 0
|
|
|
+ elif exp[0] == 'sum':
|
|
|
+ return sum(evl(t, lookup) for t in exp[1])
|
|
|
+ raise Exception("Not allowed: {}".format(exp[0]))
|
|
|
+
|
|
|
+def max_val(exp, minv=False):
|
|
|
+ if exp[0] == 'c':
|
|
|
+ return exp[1]
|
|
|
+ elif exp[0] == 'in':
|
|
|
+ return 1 if minv else 9
|
|
|
+ elif exp[0] == 'add':
|
|
|
+ return max_val(exp[1], minv) + max_val(exp[2], minv)
|
|
|
+ elif exp[0] == 'mul':
|
|
|
+ return max_val(exp[1], minv) * max_val(exp[2], minv)
|
|
|
+ elif exp[0] == 'div':
|
|
|
+ return floor(max_val(exp[1], minv) / max_val(exp[2], not minv))
|
|
|
+ elif exp[0] == 'mod':
|
|
|
+ return (max_val(exp[2]) - 1) if not minv else 0
|
|
|
+ elif exp[0] == 'eql':
|
|
|
+ return 0 if minv else 1
|
|
|
+ elif exp[0] == 'sum':
|
|
|
+ return sum(max_val(t, minv) for t in exp[1])
|
|
|
+ raise Exception("Not allowed: {}".format(exp[0]))
|
|
|
+
|
|
|
+def reduce_sum(terms):
|
|
|
+ indices = [i for (i, t) in enumerate(terms) if t[0] == 'c']
|
|
|
+ if len(indices) == 2:
|
|
|
+ terms[indices[0]] = ('c', terms[indices[0]][1] + terms[indices[1]][1])
|
|
|
+ terms.pop(indices[1])
|
|
|
+ return [t for t in terms if t != ('c', 0)]
|
|
|
+
|
|
|
+def simplify(exp):
|
|
|
+ global lookup
|
|
|
+ if exp[0] == 'sum':
|
|
|
+ s = reduce_sum([simplify(t) for t in exp[1]])
|
|
|
+ if len(s) == 1:
|
|
|
+ return s[0]
|
|
|
+ else:
|
|
|
+ return ('sum', s)
|
|
|
+ elif exp[0] == 'add':
|
|
|
+ if exp[1][0] == 'sum' and exp[2][0] == 'sum':
|
|
|
+ return simplify(('sum', exp[1][1] + exp[2][1]))
|
|
|
+ elif exp[1][0] == 'sum':
|
|
|
+ return simplify(('sum', exp[1][1] + [exp[2]]))
|
|
|
+ elif exp[2][0] == 'sum':
|
|
|
+ return simplify(('sum', [exp[1]] + exp[2][1]))
|
|
|
+ else:
|
|
|
+ return simplify(('sum', [exp[1], exp[2]]))
|
|
|
+ elif exp[0] == 'mul':
|
|
|
+ if exp[2] == ('c', 0) or exp[1] == ('c', 0):
|
|
|
+ return ('c', 0)
|
|
|
+ if exp[2] == ('c', 1):
|
|
|
+ return exp[1]
|
|
|
+ if exp[1] == ('c', 1):
|
|
|
+ return exp[2]
|
|
|
+ if exp[1][0] == 'div' and exp[1][2] == exp[2]:
|
|
|
+ return exp[1][1]
|
|
|
+ if exp[1][0] == 'c' and exp[2][0] == 'c':
|
|
|
+ return ('c', exp[1][1] * exp[2][1])
|
|
|
+ elif exp[0] == 'div':
|
|
|
+ if exp[2] == ('c', 1):
|
|
|
+ return exp[1]
|
|
|
+ if exp[1][0] == 'c' and exp[2][0] == 'c':
|
|
|
+ return ('c', floor(exp[1][1] / exp[2][1]))
|
|
|
+ if exp[2][0] == 'c' and max_val(exp[1]) < exp[2][1]:
|
|
|
+ return ('c', 0)
|
|
|
+ if exp[1][0] == 'mul' and exp[1][2] == exp[2]:
|
|
|
+ return exp[1][1]
|
|
|
+ if exp[1][0] == 'sum':
|
|
|
+ indices = [i for i, t in enumerate(exp[1][1]) if t[0] == 'mul' and t[2] == exp[2]]
|
|
|
+ if len(indices) > 0:
|
|
|
+ terms = exp[1][1]
|
|
|
+ term = terms[indices[0]][1]
|
|
|
+ terms.pop(indices[0])
|
|
|
+ return simplify(('sum', [term] + [('div', ('sum', terms), exp[2])]))
|
|
|
+ elif exp[0] == 'mod':
|
|
|
+ if exp[1][0] == 'c' and exp[2][0] == 'c':
|
|
|
+ return ('c', exp[1][1] % exp[2][1])
|
|
|
+ if exp[2][0] == 'c' and max_val(exp[1]) < exp[2][1]:
|
|
|
+ return exp[1]
|
|
|
+ if exp[1][0] == 'mul' and exp[1][1] == exp[2]:
|
|
|
+ return ('c', 0)
|
|
|
+ if exp[1][0] == 'mul' and exp[1][2] == exp[2]:
|
|
|
+ return ('c', 0)
|
|
|
+ if exp[1][0] == 'sum':
|
|
|
+ return simplify(('sum', [('mod', t, exp[2]) for t in exp[1][1] if not (t[0] == 'mul' and t[2] == exp[2])]))
|
|
|
+ elif exp[0] == 'eql':
|
|
|
+ if exp[1] == exp[2]:
|
|
|
+ return ('c', 1)
|
|
|
+ try:
|
|
|
+ if evl(exp[1], lookup) == evl(exp[2], lookup):
|
|
|
+ print(pprint(exp[1]), 'EQUALS', pprint(exp[2]))
|
|
|
+ return ('c', 1)
|
|
|
+ except KeyError:
|
|
|
+ pass
|
|
|
+ if max_val(exp[1]) < max_val(exp[2], True):
|
|
|
+ #print("1Reduced", pprint(exp[1]), "<>", pprint(exp[2]))
|
|
|
+ return ('c', 0)
|
|
|
+ if max_val(exp[2]) < max_val(exp[1], True):
|
|
|
+ #print("2Reduced", pprint(exp[1]), "<>", pprint(exp[2]))
|
|
|
+ return ('c', 0)
|
|
|
+ #print(pprint(exp))
|
|
|
+ return exp
|
|
|
+
|
|
|
+def run(input):
|
|
|
+ var = {
|
|
|
+ 'x': ("c", 0),
|
|
|
+ 'y': ("c", 0),
|
|
|
+ 'z': ("c", 0),
|
|
|
+ 'w': ("c", 0),
|
|
|
+ }
|
|
|
+ input_idx = 0
|
|
|
+ for i, line in enumerate(input[:270]):
|
|
|
+ #print(i + 1, "/", len(input))
|
|
|
+ l = line.split()
|
|
|
+ if l[0] == 'inp':
|
|
|
+ var[l[1]] = ("in", input_idx)
|
|
|
+ input_idx += 1
|
|
|
+ else:
|
|
|
+ try:
|
|
|
+ val = ("c", int(l[2]))
|
|
|
+ except ValueError:
|
|
|
+ val = var[l[2]]
|
|
|
+ var[l[1]] = simplify((l[0], deepcopy(var[l[1]]), deepcopy(val)))
|
|
|
+ print(pprint(var['z']).replace("*", "*\n"))
|
|
|
+ print(max_val(var['z'], True))
|
|
|
+ print(evl(var['z'], lookup))
|
|
|
+ #print(max_val(var['z']))
|
|
|
+
|
|
|
+run(input)
|
|
|
+
|
|
|
+print("Part 1:", part1)
|
|
|
+print("Part 2:", part2)
|