|
|
@@ -0,0 +1,103 @@
|
|
|
+#!/usr/bin/env python3
|
|
|
+import sys
|
|
|
+from operator import add, mul, floordiv, mod, eq
|
|
|
+
|
|
|
+OPS = {'add': add, 'mul': mul, 'div': floordiv, 'mod': mod, 'eql': eq}
|
|
|
+
|
|
|
+def isoffset(e):
|
|
|
+ return isinstance(e, Expr) \
|
|
|
+ and e.opcode == 'add' \
|
|
|
+ and isinstance(e.right, int) \
|
|
|
+ and isinstance(e.left, Expr) \
|
|
|
+ and e.left.opcode == 'inp'
|
|
|
+
|
|
|
+class Expr:
|
|
|
+ def __init__(self, opcode, left, right):
|
|
|
+ self.opcode = opcode
|
|
|
+ self.left = left
|
|
|
+ self.right = right
|
|
|
+
|
|
|
+ def reduce(self, conditions):
|
|
|
+ lconst = isinstance(self.left, int)
|
|
|
+ rconst = isinstance(self.right, int)
|
|
|
+
|
|
|
+ if lconst and rconst:
|
|
|
+ return int(OPS[self.opcode](self.left, self.right))
|
|
|
+ elif lconst and self.opcode in ('add', 'mul', 'eql'):
|
|
|
+ return Expr(self.opcode, self.right, self.left).reduce(conditions)
|
|
|
+
|
|
|
+ if self.opcode == 'add':
|
|
|
+ if self.right == 0:
|
|
|
+ return self.left
|
|
|
+ if rconst and self.left.opcode == 'add' and isinstance(self.left.right, int):
|
|
|
+ return Expr('add', self.left.left, self.left.right + self.right)
|
|
|
+ elif self.opcode == 'mul':
|
|
|
+ if self.right == 0:
|
|
|
+ return 0
|
|
|
+ if self.right == 1:
|
|
|
+ return self.left
|
|
|
+ elif self.opcode == 'eql':
|
|
|
+ if rconst:
|
|
|
+ if self.left.opcode == 'inp' and self.right < 1 or self.right > 9:
|
|
|
+ return 0
|
|
|
+ elif self.right.opcode == 'inp':
|
|
|
+ if self.left.opcode == 'add' \
|
|
|
+ and isinstance(self.left.right, int) \
|
|
|
+ and self.left.right > 9:
|
|
|
+ return 0
|
|
|
+ else:
|
|
|
+ assert isoffset(self.left)
|
|
|
+ index_a = self.left.left.left
|
|
|
+ offset = self.left.right
|
|
|
+ index_b = self.right.left
|
|
|
+ assert index_a < index_b
|
|
|
+ conditions.append((index_a, index_b, offset))
|
|
|
+ return 1
|
|
|
+ elif self.opcode == 'div':
|
|
|
+ if self.right == 1:
|
|
|
+ return self.left
|
|
|
+ if rconst and self.left.opcode == 'add' \
|
|
|
+ and isoffset(self.left.right) \
|
|
|
+ and self.left.left.opcode == 'mul' \
|
|
|
+ and self.left.left.right == self.right:
|
|
|
+ return self.left.left.left
|
|
|
+ elif self.opcode == 'mod':
|
|
|
+ if self.left.opcode == 'add' and self.right == 26:
|
|
|
+ return self.left if isoffset(self.left) else self.left.right
|
|
|
+
|
|
|
+ return self
|
|
|
+
|
|
|
+def parse(line):
|
|
|
+ parts = line.split()
|
|
|
+ if len(parts) == 2:
|
|
|
+ operand = None
|
|
|
+ elif parts[2].isdigit() or parts[2].startswith('-'):
|
|
|
+ operand = int(parts[2])
|
|
|
+ else:
|
|
|
+ operand = parts[2]
|
|
|
+ return parts[0], parts[1], operand
|
|
|
+
|
|
|
+def input_conditions(program):
|
|
|
+ conditions = []
|
|
|
+ regs = {'w': 0, 'x': 0, 'y': 0, 'z': 0}
|
|
|
+ index = 0
|
|
|
+ for opcode, reg, operand in program:
|
|
|
+ if opcode == 'inp':
|
|
|
+ regs[reg] = Expr('inp', index, None)
|
|
|
+ index += 1
|
|
|
+ else:
|
|
|
+ if not isinstance(operand, int):
|
|
|
+ operand = regs[operand]
|
|
|
+ regs[reg] = Expr(opcode, regs[reg], operand).reduce(conditions)
|
|
|
+ return conditions
|
|
|
+
|
|
|
+def modelnum(conditions, largest):
|
|
|
+ nr = [0] * 14
|
|
|
+ for a, b, offset in conditions:
|
|
|
+ nr[a] = 9 - max(offset, 0) if largest else 1 - min(offset, 0)
|
|
|
+ nr[b] = nr[a] + offset
|
|
|
+ return ''.join(map(str, nr))
|
|
|
+
|
|
|
+conditions = input_conditions(map(parse, sys.stdin))
|
|
|
+print(modelnum(conditions, True))
|
|
|
+print(modelnum(conditions, False))
|