-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathintcode.py
More file actions
167 lines (135 loc) · 4.34 KB
/
Copy pathintcode.py
File metadata and controls
167 lines (135 loc) · 4.34 KB
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
from typing import List, Optional, Tuple
from collections import deque
from dataclasses import dataclass
class Mem(list):
def resolve_ptr(self, mode: int, ptr: int, rptr: int) -> int:
if mode == 0:
ptr = self[ptr]
elif mode == 1:
ptr = ptr
elif mode == 2:
ptr = self[ptr] + rptr
else:
raise Exception(f'unknown mode: {mode}')
return ptr
def check_mem(self, ptr: int) -> None:
if ptr < 0:
raise Exception(f'negative pointer: f{ptr}')
if ptr >= len(self):
self += [0] * ((ptr + 1) - len(self))
def get(self, mode: int, ptr: int, rptr: int) -> int:
ptr = self.resolve_ptr(mode, ptr, rptr)
self.check_mem(ptr)
return Addr(self, mode, ptr)
@dataclass
class Addr:
mem: Mem
mode: int
ptr: int
def read(self) -> int:
return self.mem[self.ptr]
def write(self, value: int):
if self.mode == 1:
raise Exception(f'immediate write: {self.ptr}: {value}')
self.mem[self.ptr] = value
class Emulator:
def __init__(self, program: List[int], input: Optional[deque] = None, output: Optional[deque] = None):
self.mem = Mem(program)
self.input = input
self.ptr = 0
self.rptr = 0
self.output = output
self.stopped = False
if self.input is None:
self.input = deque()
if self.output is None:
self.output = deque()
self._op_funcs = {
99: self._break,
1: self._add,
2: self._mul,
3: self._input,
4: self._output,
5: self._jumptrue,
6: self._jumpfalse,
7: self._lessthan,
8: self._equals,
9: self._rel_base_offset,
}
def _p(self, count: int, modes: List[int]) -> List[Addr]:
return [self.mem.get(modes[i], self.ptr + i, self.rptr) for i in range(count)]
def _parse_instruction(self, instruction: int) -> Tuple[int, List[int]]:
op = instruction % 100
modes = [
instruction // 100 % 10,
instruction // 1000 % 10,
instruction // 10000 % 10,
]
return op, modes
def run(self) -> None:
while not self.stopped:
if not self.step():
return
def step(self) -> bool:
op, modes = self._parse_instruction(
self.mem.get(1, self.ptr, self.rptr).read()
)
self.ptr += 1
if op not in self._op_funcs:
raise Exception(f'invalid opcode: {op}')
return self._op_funcs[op](modes)
def _break(self, modes: List[int]) -> bool:
self.stopped = True
return False
def _add(self, modes: List[int]) -> bool:
p = self._p(3, modes)
self.ptr += 3
p[2].write(p[0].read() + p[1].read())
return True
def _mul(self, modes: List[int]) -> bool:
p = self._p(3, modes)
self.ptr += 3
p[2].write(p[0].read() * p[1].read())
return True
def _input(self, modes: List[int]) -> bool:
try:
input = self.input.popleft()
except IndexError:
self.ptr -= 1
return False
p = self._p(1, modes)
self.ptr += 1
p[0].write(input)
return True
def _output(self, modes: List[int]) -> bool:
p = self._p(1, modes)
self.ptr += 1
self.output.append(p[0].read())
return True
def _jumptrue(self, modes: List[int]) -> bool:
p = self._p(2, modes)
self.ptr += 2
if p[0].read() != 0:
self.ptr = p[1].read()
return True
def _jumpfalse(self, modes: List[int]) -> bool:
p = self._p(2, modes)
self.ptr += 2
if p[0].read() == 0:
self.ptr = p[1].read()
return True
def _lessthan(self, modes: List[int]) -> bool:
p = self._p(3, modes)
self.ptr += 3
p[2].write(int(p[0].read() < p[1].read()))
return True
def _equals(self, modes: List[int]) -> bool:
p = self._p(3, modes)
self.ptr += 3
p[2].write(int(p[0].read() == p[1].read()))
return True
def _rel_base_offset(self, modes: List[int]) -> bool:
p = self._p(1, modes)
self.ptr += 1
self.rptr += p[0].read()
return True