|
@@ -1,36 +1,34 @@
|
|
1
|
+import operator
|
1
|
2
|
from collections import defaultdict
|
2
|
3
|
|
3
|
|
-get_value = lambda registers, operand: registers[operand] if operand in registers else int(operand)
|
4
|
4
|
|
5
|
|
-def handle_snd(pc, registers, state, args):
|
6
|
|
- state['snd'].append(get_value(registers, args[0]))
|
7
|
|
- state['sndc'] += 1
|
8
|
|
- return pc + 1
|
|
5
|
+def get_value(registers, operand):
|
|
6
|
+ return registers[operand] if operand in registers else int(operand)
|
9
|
7
|
|
10
|
|
-def handle_set(pc, registers, state, args):
|
11
|
|
- registers[args[0]] = get_value(registers, args[1])
|
12
|
|
- return pc + 1
|
13
|
8
|
|
14
|
|
-def handle_add(pc, registers, state, args):
|
15
|
|
- registers[args[0]] += get_value(registers, args[1])
|
16
|
|
- return pc + 1
|
|
9
|
+def handle_generic(op):
|
|
10
|
+ def inner(pc, registers, _, args):
|
|
11
|
+ registers[args[0]] = op(registers[args[0]], get_value(registers, args[1]))
|
|
12
|
+ return pc + 1
|
|
13
|
+ return inner
|
17
|
14
|
|
18
|
|
-def handle_mul(pc, registers, state, args):
|
19
|
|
- registers[args[0]] *= get_value(registers, args[1])
|
20
|
|
- return pc + 1
|
21
|
15
|
|
22
|
|
-def handle_mod(pc, registers, state, args):
|
23
|
|
- registers[args[0]] %= get_value(registers, args[1])
|
|
16
|
+def handle_snd(pc, registers, state, args):
|
|
17
|
+ state['snd'].append(get_value(registers, args[0]))
|
|
18
|
+ state['sndc'] += 1
|
24
|
19
|
return pc + 1
|
25
|
20
|
|
26
|
|
-def handle_jgz(pc, registers, state, args):
|
|
21
|
+
|
|
22
|
+def handle_jgz(pc, registers, _, args):
|
27
|
23
|
return pc + get_value(registers, args[1]) if get_value(registers, args[0]) > 0 else pc + 1
|
28
|
24
|
|
|
25
|
+
|
29
|
26
|
def handle_rcv_p1(pc, registers, state, args):
|
30
|
27
|
if get_value(registers, args[0]) != 0:
|
31
|
|
- state['recovered'].append(state['snd'][-1])
|
|
28
|
+ state['rcv'].append(state['snd'][-1])
|
32
|
29
|
return pc + 1
|
33
|
30
|
|
|
31
|
+
|
34
|
32
|
def handle_rcv_p2(pc, registers, state, args):
|
35
|
33
|
if len(state['rcv']) > 0:
|
36
|
34
|
registers[args[0]] = state['rcv'].pop(0)
|
|
@@ -38,73 +36,62 @@ def handle_rcv_p2(pc, registers, state, args):
|
38
|
36
|
else:
|
39
|
37
|
return pc
|
40
|
38
|
|
41
|
|
-def process_p1(instructions):
|
42
|
|
- pc, state, registers = 0, {'snd': [], 'sndc': 0, 'recovered': []}, defaultdict(lambda: 0)
|
43
|
|
- ops = {
|
|
39
|
+
|
|
40
|
+def get_ops(part_one=True):
|
|
41
|
+ return {
|
44
|
42
|
'snd': handle_snd,
|
45
|
|
- 'set': handle_set,
|
46
|
|
- 'add': handle_add,
|
47
|
|
- 'mul': handle_mul,
|
48
|
|
- 'mod': handle_mod,
|
|
43
|
+ 'set': handle_generic(lambda _, v: v),
|
|
44
|
+ 'add': handle_generic(operator.add),
|
|
45
|
+ 'mul': handle_generic(operator.mul),
|
|
46
|
+ 'mod': handle_generic(operator.mod),
|
49
|
47
|
'jgz': handle_jgz,
|
50
|
|
- 'rcv': handle_rcv_p1,
|
|
48
|
+ 'rcv': handle_rcv_p1 if part_one else handle_rcv_p2
|
51
|
49
|
}
|
52
|
|
- while len(state['recovered']) == 0:
|
53
|
|
- ins = instructions[pc]
|
54
|
|
- pc = ops[ins[0]](pc, registers, state, ins[1:])
|
55
|
|
- return state['recovered'][0]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+def new_program(snd, rcv):
|
|
53
|
+ return {'pc': 0, 'snd': snd, 'sndc': 0, 'rcv': rcv, 'terminated': False, 'waiting': False, 'regs': defaultdict(lambda: 0)}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+def process_p1(instructions):
|
|
57
|
+ program = new_program([], [])
|
|
58
|
+ ops = get_ops(True)
|
|
59
|
+ while len(program['rcv']) == 0:
|
|
60
|
+ ins = instructions[program['pc']]
|
|
61
|
+ program['pc'] = ops[ins[0]](program['pc'], program['regs'], program, ins[1:])
|
|
62
|
+ return program['rcv'][0]
|
56
|
63
|
|
57
|
64
|
|
58
|
65
|
def can_execute(programs):
|
59
|
|
- for p in programs:
|
60
|
|
- if p['state']['terminated']:
|
61
|
|
- yield False
|
62
|
|
- elif p['state']['waiting'] and len(p['state']['rcv']) == 0:
|
63
|
|
- yield False
|
64
|
|
- else:
|
65
|
|
- yield True
|
|
66
|
+ return any(not p['terminated'] and (not p['waiting'] or len(p['rcv']) > 0) for p in programs)
|
66
|
67
|
|
67
|
68
|
|
68
|
69
|
def process_p2(instructions):
|
69
|
70
|
p1_to_p2, p2_to_p1 = [], []
|
70
|
|
- programs = [{
|
71
|
|
- 'pc': 0,
|
72
|
|
- 'state': {'snd': p1_to_p2, 'sndc': 0, 'rcv': p2_to_p1, 'terminated': False, 'waiting': False},
|
73
|
|
- 'regs': defaultdict(lambda: 0)
|
74
|
|
- }, {
|
75
|
|
- 'pc': 0,
|
76
|
|
- 'state': {'snd': p2_to_p1, 'sndc': 0, 'rcv': p1_to_p2, 'terminated': False, 'waiting': False},
|
77
|
|
- 'regs': defaultdict(lambda: 0),
|
78
|
|
- }]
|
|
71
|
+ programs = [new_program(p1_to_p2, p2_to_p1), new_program(p2_to_p1, p1_to_p2)]
|
79
|
72
|
programs[1]['regs']['p'] = 1
|
80
|
73
|
|
81
|
|
- ops = {
|
82
|
|
- 'snd': handle_snd,
|
83
|
|
- 'set': handle_set,
|
84
|
|
- 'add': handle_add,
|
85
|
|
- 'mul': handle_mul,
|
86
|
|
- 'mod': handle_mod,
|
87
|
|
- 'jgz': handle_jgz,
|
88
|
|
- 'rcv': handle_rcv_p2,
|
89
|
|
- }
|
90
|
|
-
|
|
74
|
+ ops = get_ops(False)
|
91
|
75
|
p = 0
|
92
|
|
- while any(can_execute(programs)):
|
|
76
|
+ while can_execute(programs):
|
93
|
77
|
for _ in range(1000):
|
94
|
78
|
pc = programs[p]['pc']
|
95
|
|
- programs[p]['state']['waiting'] = False
|
|
79
|
+ programs[p]['waiting'] = False
|
|
80
|
+
|
96
|
81
|
if pc < 0 or pc >= len(instructions):
|
97
|
|
- programs[p]['state']['terminated'] = True
|
|
82
|
+ programs[p]['terminated'] = True
|
98
|
83
|
break
|
|
84
|
+
|
99
|
85
|
ins = instructions[pc]
|
100
|
|
- programs[p]['pc'] = ops[ins[0]](pc, programs[p]['regs'], programs[p]['state'], ins[1:])
|
|
86
|
+ programs[p]['pc'] = ops[ins[0]](pc, programs[p]['regs'], programs[p], ins[1:])
|
|
87
|
+
|
101
|
88
|
if programs[p]['pc'] == pc:
|
102
|
|
- programs[p]['state']['waiting'] = True
|
|
89
|
+ programs[p]['waiting'] = True
|
103
|
90
|
break
|
104
|
|
- p = 1 - p
|
105
|
91
|
|
106
|
|
- return programs[1]['state']['sndc']
|
|
92
|
+ p = 1 - p
|
107
|
93
|
|
|
94
|
+ return programs[1]['sndc']
|
108
|
95
|
|
109
|
96
|
|
110
|
97
|
with open('data/18.txt', 'r') as file:
|