Skip to content

Instantly share code, notes, and snippets.

@bbeck
Last active January 2, 2020 17:37
Show Gist options
  • Save bbeck/19f355cb503fbc0c902b08a1b8889e1f to your computer and use it in GitHub Desktop.
Save bbeck/19f355cb503fbc0c902b08a1b8889e1f to your computer and use it in GitHub Desktop.
Advent of Code 2019 - Multiprocessing based IntCode CPU implementation
#!/usr/bin/env python3
import multiprocessing
class CPU(multiprocessing.Process):
def __init__(self, memory, input=None, output=None):
super(CPU, self).__init__()
self.memory = memory
self.input = input
self.output = output
self.ip = 0
self.stopped = False
def run(self):
while not self.stopped:
self.step()
def read(self, address, mode):
if mode == 0: # position mode
return self.memory[address]
elif mode == 1: # immediate mode
return address
else:
raise Exception(f"unrecognized parameter mode (read): {mode}")
def write(self, address, value, mode):
if mode == 0: # position mode
self.memory[address] = value
else:
raise Exception(f"unrecognized parameter mode (write): {mode}")
def step(self):
instruction = self.memory[self.ip]
op = instruction % 100
a_mode = (instruction // 100) % 10
b_mode = (instruction // 1000) % 10
c_mode = (instruction // 10000) % 10
if op == 1: # add
a = self.memory[self.ip+1]
b = self.memory[self.ip+2]
c = self.memory[self.ip+3]
self.write(c, self.read(a, a_mode) + self.read(b, b_mode), c_mode)
self.ip += 4
elif op == 2: # mul
a = self.memory[self.ip+1]
b = self.memory[self.ip+2]
c = self.memory[self.ip+3]
self.write(c, self.read(a, a_mode) * self.read(b, b_mode), c_mode)
self.ip += 4
elif op == 3: # in
a = self.memory[self.ip+1]
self.write(a, self.input(), a_mode)
self.ip += 2
elif op == 4: # out
a = self.memory[self.ip+1]
self.output(self.read(a, a_mode))
self.ip += 2
elif op == 5: # jump if true
a = self.memory[self.ip+1]
b = self.memory[self.ip+2]
self.ip = self.read(b, b_mode) if self.read(a, a_mode) != 0 else self.ip+3
elif op == 6: # jump if false
a = self.memory[self.ip+1]
b = self.memory[self.ip+2]
self.ip = self.read(b, b_mode) if self.read(a, a_mode) == 0 else self.ip+3
elif op == 7: # less than
a = self.memory[self.ip+1]
b = self.memory[self.ip+2]
c = self.memory[self.ip+3]
if self.read(a, a_mode) < self.read(b, b_mode):
self.write(c, 1, c_mode)
else:
self.write(c, 0, c_mode)
self.ip += 4
elif op == 8: # equal
a = self.memory[self.ip+1]
b = self.memory[self.ip+2]
c = self.memory[self.ip+3]
if self.read(a, a_mode) == self.read(b, b_mode):
self.write(c, 1, c_mode)
else:
self.write(c, 0, c_mode)
self.ip += 4
elif op == 99: # halt
self.stopped = True
else:
raise Exception(f"unrecognized op code: {op}")
#################################
# Different ways to run the CPU
#################################
program = [1,0,0,0,99]
# To run a program in a blocking fashion...
memory = program[:]
blocking = CPU(memory)
blocking.run()
print(f"call blocking: 1 + 1 = {memory[0]}")
# To run a program in a non-blocking fashion...be careful here, the memory is
# modified in a subprocess so changes to it aren't visible to the calling
# process.
memory = program[:]
nonblocking = CPU(memory)
nonblocking.start()
nonblocking.join()
print(f"call nonblocking (built-in list): 1 + 1 = {memory[0]}")
# To make the memory contents visible to the calling process you can instead use
# a multiprocessing.Array of integers to hold the memory contents.
memory = multiprocessing.Array("i", program)
array = CPU(memory)
array.start()
array.join()
print(f"call nonblocking (array): 1 + 1 = {memory[0]}")
#################################
# Inputting and outputting values
#################################
program = [3,0,4,0,99]
# Values can be passed in/out via a function
memory = program[:]
function = CPU(memory, lambda: 9876, lambda out: print(f"pass via function: {out}"))
function.run()
# Values can also be passed in/out via a queue...this will also work either
# in process or out of process.
q = multiprocessing.Queue()
q.put(9876)
memory = program[:]
queue = CPU(memory, q.get, q.put)
queue.start(); queue.join()
print(f"pass via queue: {q.get()}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment