18_duet.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. #!/usr/bin/env python3
  2. import sys
  3. from collections import defaultdict, deque
  4. def parse(f):
  5. def maybe_reg(op):
  6. return op if op.isalpha() else int(op)
  7. for line in f:
  8. parts = line.split()
  9. opcode = parts[0]
  10. a = maybe_reg(parts[1])
  11. b = maybe_reg(parts[2]) if len(parts) == 3 else None
  12. yield opcode, a, b
  13. def run(program, progid, part1=False):
  14. def value(val):
  15. return regs[val] if isinstance(val, str) else val
  16. regs = defaultdict(int)
  17. regs['p'] = progid
  18. sent = deque()
  19. received = deque()
  20. pc = 0
  21. while pc < len(program):
  22. opcode, a, b = program[pc]
  23. if opcode == 'snd':
  24. sent.append(value(a))
  25. elif opcode == 'set':
  26. regs[a] = value(b)
  27. elif opcode == 'add':
  28. regs[a] += value(b)
  29. elif opcode == 'mul':
  30. regs[a] *= value(b)
  31. elif opcode == 'mod':
  32. regs[a] %= value(b)
  33. elif opcode == 'rcv' and part1:
  34. if value(a):
  35. yield sent[-1]
  36. elif opcode == 'rcv':
  37. while not received:
  38. received = yield sent
  39. sent = deque()
  40. regs[a] = received.popleft()
  41. elif opcode == 'jgz' and value(a) > 0:
  42. pc += value(b) - 1
  43. pc += 1
  44. # part 1
  45. program = list(parse(sys.stdin))
  46. print(next(run(program, 0, True)))
  47. # part 2
  48. prog0 = run(program, 0)
  49. prog1 = run(program, 1)
  50. q0 = next(prog0)
  51. q1 = next(prog1)
  52. sent1 = len(q1)
  53. while q0 or q1:
  54. q0, q1 = prog0.send(q1), prog1.send(q0)
  55. sent1 += len(q1)
  56. print(sent1)