Solutions to Advent of Code 2017 https://adventofcode.com/2017/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

18.py 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import operator
  2. from collections import defaultdict
  3. def get_value(registers, operand):
  4. return registers[operand] if operand in registers else int(operand)
  5. def handle_generic(op):
  6. def inner(pc, registers, _, args):
  7. registers[args[0]] = op(registers[args[0]], get_value(registers, args[1]))
  8. return pc + 1
  9. return inner
  10. def handle_snd(pc, registers, state, args):
  11. state['snd'].append(get_value(registers, args[0]))
  12. state['sndc'] += 1
  13. return pc + 1
  14. def handle_jgz(pc, registers, _, args):
  15. return pc + get_value(registers, args[1]) if get_value(registers, args[0]) > 0 else pc + 1
  16. def handle_rcv_p1(pc, registers, state, args):
  17. if get_value(registers, args[0]) != 0:
  18. state['rcv'].append(state['snd'][-1])
  19. return pc + 1
  20. def handle_rcv_p2(pc, registers, state, args):
  21. if len(state['rcv']) > 0:
  22. registers[args[0]] = state['rcv'].pop(0)
  23. return pc + 1
  24. else:
  25. return pc
  26. def get_ops(part_one=True):
  27. return {
  28. 'snd': handle_snd,
  29. 'set': handle_generic(lambda _, v: v),
  30. 'add': handle_generic(operator.add),
  31. 'mul': handle_generic(operator.mul),
  32. 'mod': handle_generic(operator.mod),
  33. 'jgz': handle_jgz,
  34. 'rcv': handle_rcv_p1 if part_one else handle_rcv_p2
  35. }
  36. def new_program(snd, rcv):
  37. return {'pc': 0, 'snd': snd, 'sndc': 0, 'rcv': rcv, 'terminated': False, 'waiting': False, 'regs': defaultdict(lambda: 0)}
  38. def process_p1(instructions):
  39. program = new_program([], [])
  40. ops = get_ops(True)
  41. while len(program['rcv']) == 0:
  42. ins = instructions[program['pc']]
  43. program['pc'] = ops[ins[0]](program['pc'], program['regs'], program, ins[1:])
  44. return program['rcv'][0]
  45. def can_execute(programs):
  46. return any(not p['terminated'] and (not p['waiting'] or len(p['rcv']) > 0) for p in programs)
  47. def process_p2(instructions):
  48. p1_to_p2, p2_to_p1 = [], []
  49. programs = [new_program(p1_to_p2, p2_to_p1), new_program(p2_to_p1, p1_to_p2)]
  50. programs[1]['regs']['p'] = 1
  51. ops = get_ops(False)
  52. p = 0
  53. while can_execute(programs):
  54. for _ in range(1000):
  55. pc = programs[p]['pc']
  56. programs[p]['waiting'] = False
  57. if pc < 0 or pc >= len(instructions):
  58. programs[p]['terminated'] = True
  59. break
  60. ins = instructions[pc]
  61. programs[p]['pc'] = ops[ins[0]](pc, programs[p]['regs'], programs[p], ins[1:])
  62. if programs[p]['pc'] == pc:
  63. programs[p]['waiting'] = True
  64. break
  65. p = 1 - p
  66. return programs[1]['sndc']
  67. with open('data/18.txt', 'r') as file:
  68. input = list(map(str.split, file.readlines()))
  69. print(f'Part one: {process_p1(input)}')
  70. print(f'Part two: {process_p2(input)}')