-
Notifications
You must be signed in to change notification settings - Fork 0
/
day07.py
101 lines (83 loc) · 2.71 KB
/
day07.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import re
from collections import defaultdict, namedtuple, Counter
from pprint import pprint
class Operation:
def __init__(self, args, opcode, result):
self.result = result
self.opcode = opcode
self.args = args
self.a, *_ = args
self.executed = False
def can_execute(self, wires):
valid_a = type(self.a) is int or self.a in wires
valid_b = type(self.b) is int or self.b in wires or len(self.args) == 1
return not self.executed and valid_a and valid_b
def execute(self, wires):
# print(self)
if self.result not in wires:
a = self.a if type(self.a) is int else wires.get(self.a, None)
b = self.b if type(self.b) is int else wires.get(self.b, None)
if self.opcode == 'LET':
ret = a
elif self.opcode == 'LSHIFT':
ret = a << b
elif self.opcode == 'RSHIFT':
ret = a >> b
elif self.opcode == 'AND':
ret = a & b
elif self.opcode == 'OR':
ret = a | b
elif self.opcode == 'NOT':
ret = ~a
else:
raise ValueError(self.opcode)
wires[self.result] = ret & 0xffff
self.executed = True
@property
def b(self):
return self.args[1] if len(self.args) == 2 else None
def __str__(self):
return f'{self.a} {self.opcode} {self.b} -> {self.result}'
def str_to_int(s):
try:
return int(s)
except ValueError:
return s
def parse(s: str) -> Operation:
"""
x -> y
x AND y -> z
x OR y -> z
x LSHIFT y -> z
x RSHIFT y -> z
NOT x -> y
:param s:
:return:
"""
left, result = s.split('->')
left, result = left.strip(), result.strip()
left = left.split()
ret = None
if len(left) == 1:
ret = Operation(opcode='LET', args=[str_to_int(left[0])], result=result)
elif len(left) == 2 and left[0] == 'NOT':
ret = Operation(opcode='NOT', args=[left[1]], result=result)
elif len(left) == 3 and left[1] in ('AND', 'OR', 'LSHIFT', 'RSHIFT'):
ret = Operation(opcode=left[1], args=[str_to_int(left[0]), str_to_int(left[2])], result=result)
else:
raise ValueError(f'{s} is invalid instruction')
return ret
def execute(ops, wires):
while not all(op.executed for op in ops):
for op in ops:
if op.can_execute(wires):
op.execute(wires)
ops = list(map(parse, open('07.txt').readlines())) # type: list[Operation]
wires = dict()
execute(ops, wires)
print('a: ', wires['a'])
wires2 = {'b': wires['a']}
for op in ops:
op.executed = False
execute(ops, wires2)
print('b: ', wires2['a'])