Skip to content

Instantly share code, notes, and snippets.

@killjoy1221
Last active December 5, 2019 15:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save killjoy1221/7d31ceb1d74c221138e130cd19f70a24 to your computer and use it in GitHub Desktop.
Save killjoy1221/7d31ceb1d74c221138e130cd19f70a24 to your computer and use it in GitHub Desktop.
from typing import List
import aoc
P_MODE_POSITION = 0
P_MODE_IMMEDIATE = 1
class Opcodes(dict):
def __call__(self, code):
def decorator(f):
self[code] = f
return f
return decorator
class Bytecode:
opcodes = Opcodes()
def __init__(self, memory: List[int]):
self.memory = memory
self.index = 0
def get(self, value, mode):
if mode == P_MODE_POSITION:
return self.memory[value]
if mode == P_MODE_IMMEDIATE:
return value
def set(self, position, value):
self.memory[position] = value
def jump(self, pos):
self.index = pos
def read(self, count=1):
reads = []
for i in range(count):
reads.append(self.memory[self.index])
self.index += 1
if len(reads) == 1:
return reads[0]
return tuple(reads)
@opcodes(1)
def add(self, p1_mode=0, p2_mode=0):
a, b, c = self.read(3)
self.set(c, self.get(a, p1_mode) + self.get(b, p2_mode))
@opcodes(2)
def mul(self, p1_mode=0, p2_mode=0):
a, b, c = self.read(3)
self.set(c, self.get(a, p1_mode) * self.get(b, p2_mode))
@opcodes(3)
def input(self):
a = self.read()
self.set(a, int(input("Input: ")))
@opcodes(4)
def output(self, p1_mode=0):
a = self.read()
print(self.get(a, p1_mode))
@opcodes(5)
def jump_true(self, p1_mode=0, p2_mode=0):
a, b = self.read(2)
if self.get(a, p1_mode):
self.jump(self.get(b, p2_mode))
@opcodes(6)
def jump_false(self, p1_mode=0, p2_mode=0):
a, b = self.read(2)
if not self.get(a, p1_mode):
self.jump(self.get(b, p2_mode))
@opcodes(7)
def less_than(self, p1_mode=0, p2_mode=0):
a, b, c = self.read(3)
self.set(c, int(self.get(a, p1_mode) < self.get(b, p2_mode)))
@opcodes(8)
def equals(self, p1_mode=0, p2_mode=0):
a, b, c = self.read(3)
self.set(c, int(self.get(a, p1_mode) == self.get(b, p2_mode)))
@opcodes(99)
def end(self):
exit()
def start(self):
while True:
code = self.read()
modes = [int(i) for i in str(code // 100)]
# Remove any leading 0's. Needed because 3 // 100 == 0
while modes and modes[0] == 0:
modes.pop(0)
modes.reverse()
code = code % 100
if code not in self.opcodes:
raise Exception("Unknown opcode: " + str(code))
try:
self.opcodes[code](self, *modes)
except SystemExit:
return
except TypeError:
print("code:", code, "modes:", modes)
raise
def test():
prog = Bytecode([3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8])
prog.start()
print(prog.memory)
def new_bytecode():
with aoc.open_input(__name__) as f:
memory = [int(e) for e in f.read().split(',')]
return Bytecode(memory)
def main():
new_bytecode().start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment