23_safe.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. #!/usr/bin/env python3
  2. import sys
  3. def read_program(f):
  4. maybe_int = lambda x: int(x) if x.isdigit() or x[0] == '-' else x
  5. for line in f:
  6. instr = tuple(map(maybe_int, line.split()))
  7. yield instr + (None,) * (3 - len(instr))
  8. def check_mul(p, pc):
  9. if pc <= len(p) - 5:
  10. opcodes, a, b = zip(*p[pc:pc + 5])
  11. if a[1] == a[2] and a[3] == a[4] and b[2] == -2 and b[4] == -5:
  12. if opcodes == ('inc', 'dec', 'jnz', 'dec', 'jnz'):
  13. return a[1], a[3]
  14. def run(p, init):
  15. regs = [init, 0, 0, 0]
  16. pc = 0
  17. toggle_opcode = {'inc': 'dec', 'dec': 'inc', 'tgl': 'inc',
  18. 'cpy': 'jnz', 'jnz': 'cpy'}
  19. def load(x):
  20. return x if isinstance(x, int) else regs[ord(x) - ord('a')]
  21. def store(reg, value):
  22. regs[ord(reg) - ord('a')] = value
  23. while pc < len(p):
  24. opcode, a, b = p[pc]
  25. try:
  26. if opcode == 'cpy':
  27. store(b, load(a))
  28. elif opcode == 'inc':
  29. params = check_mul(p, pc)
  30. if params:
  31. reg1, reg2 = params
  32. increment = load(reg1) * load(reg2)
  33. store(reg1, 0)
  34. store(reg2, 0)
  35. pc += 4
  36. else:
  37. increment = 1
  38. store(a, load(a) + increment)
  39. elif opcode == 'dec':
  40. store(a, load(a) - 1)
  41. elif opcode == 'jnz':
  42. if load(a):
  43. pc += load(b) - 1
  44. elif opcode == 'tgl':
  45. offset = load(a)
  46. other_opcode, other_a, other_b = p[pc + offset]
  47. p[pc + offset] = toggle_opcode[other_opcode], other_a, other_b
  48. except IndexError:
  49. pass
  50. pc += 1
  51. return regs[0]
  52. program = list(read_program(sys.stdin))
  53. print(run(program.copy(), 7))
  54. print(run(program, 12))