summaryrefslogtreecommitdiffstats
path: root/19/py/intcode.py
diff options
context:
space:
mode:
Diffstat (limited to '19/py/intcode.py')
-rw-r--r--19/py/intcode.py153
1 files changed, 153 insertions, 0 deletions
diff --git a/19/py/intcode.py b/19/py/intcode.py
new file mode 100644
index 0000000..6079250
--- /dev/null
+++ b/19/py/intcode.py
@@ -0,0 +1,153 @@
+from collections import deque
+param_amount = {1:3, 2:3, 3:1, 4:1, 5:2, 6:2, 7:3, 8:3, 9:1, 99:0}
+
+ADD = 1
+MUL = 2
+IN = 3
+OUT = 4
+JNZ = 5
+JEZ = 6
+LET = 7
+EQV = 8
+BAS = 9
+HAL = 99
+
+class Computer(object):
+ def __init__(self, program):
+ self.program = program
+ self.memory_size = len(self.program)
+
+ self.reset()
+
+ def reset(self):
+ self.memory = self.program.copy()
+ self.extra_memory = {}
+ self.instruction_cache = {}
+ self.pointer = 0
+ self.phase_read = False # for day 7
+ self.relative_base = 0
+
+ self.input = None
+ self.input_queue = deque()
+ self.output = None
+
+ self.SIG_INPUT = False
+ self.SIG_ASCII = False
+ self.SIG_OUTPUT = False
+ self.SIG_HALT = False
+
+ def parse_op(self, op):
+ # if op in self.instruction_cache:
+ # return self.instruction_cache[op]
+ code = op % 100
+ ops = str(op).zfill(param_amount[code]+2)
+ self.instruction_cache[op] = [code] + [int(x) for x in ops[:-2][::-1]]
+ return self.instruction_cache[op]
+ #return [code] + [(op // 10**(i+2)) % 10**(i+1) for i in range(param_amount[code])]
+
+ def clear_flags(self):
+ self.input = None
+ self.output = None
+
+ def write(self, addr, val):
+ if addr >= self.memory_size:
+ self.extra_memory[addr] = val
+ else:
+ self.memory[addr] = val
+
+ def get(self, addr):
+ if addr >= self.memory_size:
+ return self.extra_memory.get(addr, 0)
+ return self.memory[addr]
+
+ def get_param(self, inst, num):
+ if inst[num] == 0:
+ return self.get(self.get(self.pointer + num))
+ elif inst[num] == 1:
+ return self.get(self.pointer + num)
+ elif inst[num] == 2:
+ return self.get(self.relative_base + self.get(self.pointer + num))
+
+ def write_param(self, inst, num, val):
+ if inst[num] == 0:
+ self.write(self.get(self.pointer + num), val)
+ elif inst[num] == 1:
+ self.write(self.pointer + num, val)
+ elif inst[num] == 2:
+ self.write(self.relative_base + self.get(self.pointer + num), val)
+
+ def queue_input(self, data: list):
+ for val in data:
+ self.input_queue.append(data)
+
+ def queue_ascii(self, data: str, newline=True):
+ for c in data:
+ if c == "\n":
+ self.input_queue.append(10)
+ else:
+ self.input_queue.append(ord(c))
+ if newline:
+ self.input_queue.append(10)
+
+ def step(self):
+ if self.SIG_OUTPUT and self.output is None:
+ self.SIG_OUTPUT = False
+ if self.SIG_INPUT and self.input is not None:
+ self.SIG_INPUT = False
+
+ inst = self.parse_op(self.memory[self.pointer])
+ if inst[0] == HAL:
+ self.SIG_HALT = True
+ return
+ elif inst[0] == ADD:
+ self.write_param(inst, 3, \
+ self.get_param(inst, 1) + self.get_param(inst, 2))
+ self.pointer += 4
+ elif inst[0] == MUL:
+ self.write_param(inst, 3, \
+ self.get_param(inst, 1) * self.get_param(inst, 2))
+ self.pointer += 4
+ elif inst[0] == IN:
+ if self.SIG_ASCII and len(self.input_queue) != 0:
+ self.input = self.input_queue.popleft()
+ if self.input is None:
+ self.SIG_INPUT = True
+ return
+ self.write_param(inst, 1, self.input)
+ self.input = None
+ self.SIG_INPUT = False
+ self.pointer += 2
+ elif inst[0] == OUT:
+ if self.SIG_OUTPUT:
+ return
+ self.output = self.get_param(inst, 1)
+ self.SIG_OUTPUT = True
+ self.pointer += 2
+ elif inst[0] == JNZ:
+ if self.get_param(inst, 1) != 0:
+ self.pointer = self.get_param(inst, 2)
+ else:
+ self.pointer += 3
+ elif inst[0] == JEZ:
+ if self.get_param(inst, 1) == 0:
+ self.pointer = self.get_param(inst, 2)
+ else:
+ self.pointer += 3
+ elif inst[0] == LET:
+ self.write_param(inst, 3, 1 if \
+ self.get_param(inst, 1) < self.get_param(inst, 2) \
+ else 0)
+ self.pointer += 4
+ elif inst[0] == EQV:
+ self.write_param(inst, 3, 1 if \
+ self.get_param(inst, 1) == self.get_param(inst, 2) \
+ else 0)
+ self.pointer += 4
+ elif inst[0] == BAS:
+ self.relative_base += self.get_param(inst, 1)
+ self.pointer += 2
+ else:
+ print(self.memory)
+ print(self.pointer)
+ print("invalid instruction", self.memory[self.pointer])
+ print(inst)