24_alu.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #!/usr/bin/env python3
  2. import sys
  3. from collections import namedtuple
  4. from operator import add, mul, floordiv, mod, eq
  5. Expr = namedtuple('Expr', 'opcode, left, right')
  6. OPS = {'add': add, 'mul': mul, 'div': floordiv, 'mod': mod, 'eql': eq}
  7. def parse(line):
  8. parts = line.split()
  9. if len(parts) == 2:
  10. operand = None
  11. elif parts[2].isdigit() or parts[2].startswith('-'):
  12. operand = int(parts[2])
  13. else:
  14. operand = parts[2]
  15. return parts[0], parts[1], operand
  16. def simplify(e, constraints):
  17. lconst = isinstance(e.left, int)
  18. rconst = isinstance(e.right, int)
  19. if lconst and rconst:
  20. return int(OPS[e.opcode](e.left, e.right))
  21. elif lconst and e.opcode in ('add', 'mul', 'eql'):
  22. return simplify(Expr(e.opcode, e.right, e.left), constraints)
  23. if e.opcode == 'add':
  24. # a + 0 -> a
  25. # (a + 1) + 2 -> a + 3
  26. if e.right == 0:
  27. return e.left
  28. if e.left.opcode == 'add':
  29. return Expr('add', e.left.left, e.left.right + e.right)
  30. elif e.opcode == 'mul':
  31. # a * 0 -> 0
  32. # a * 1 -> a
  33. if e.right == 0:
  34. return 0
  35. if e.right == 1:
  36. return e.left
  37. elif e.opcode == 'eql':
  38. # ((a % 26) + larger_than_9) == inp[i] -> 0
  39. # (inp[i] + offset) == inp[j] -> 1, record constraint (i, j, offset)
  40. offset = e.left.right
  41. if rconst or offset > 9:
  42. return 0
  43. constraints.append((e.left.left.left, e.right.left, offset))
  44. return 1
  45. elif e.opcode == 'div':
  46. # a / 1 -> a
  47. # ((a * 26) + b) / 26 -> a
  48. return e.left if e.right == 1 else e.left.left.left
  49. elif e.opcode == 'mod':
  50. # (inp[i] + smaller_than_17) % 26 -> inp[i] + smaller_than_17
  51. # ((a * 26) + b) % 26 -> b
  52. return e.left if e.left.left.opcode == 'inp' else e.left.right
  53. return e
  54. def input_constraints(nomad):
  55. constraints = []
  56. regs = {'w': 0, 'x': 0, 'y': 0, 'z': 0}
  57. index = 0
  58. for opcode, reg, operand in nomad:
  59. if opcode == 'inp':
  60. regs[reg] = Expr('inp', index, None)
  61. index += 1
  62. else:
  63. if not isinstance(operand, int):
  64. operand = regs[operand]
  65. regs[reg] = simplify(Expr(opcode, regs[reg], operand), constraints)
  66. return constraints
  67. def modelnum(constraints, largest):
  68. nr = [0] * 14
  69. for a, b, offset in constraints:
  70. nr[a] = 9 - max(offset, 0) if largest else 1 - min(offset, 0)
  71. nr[b] = nr[a] + offset
  72. return ''.join(map(str, nr))
  73. constraints = input_constraints(map(parse, sys.stdin))
  74. print(modelnum(constraints, True))
  75. print(modelnum(constraints, False))