Advertisement
Guest User

IntComp.py

a guest
Dec 9th, 2019
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.25 KB | None | 0 0
  1. import collections
  2. import threading
  3.  
  4. class IntComp:
  5.     def __init__(self, program=None, input_values=None):
  6.         self.input_deque = collections.deque()
  7.         self.outputs = []  # internal record of the outputs; different from output_receiver
  8.         self.pos = 0
  9.         self.rel_base = 0
  10.        
  11.         self.output_receiver = None  # another IntComp that gets the outputs from this one
  12.         self.output_event = threading.Event()
  13.         self.output_event.set()
  14.         self.input_provider = None  # another IntComp that provides the inputs for this one
  15.         self.input_event = threading.Event()
  16.         self.input_event.set()
  17.         self.event_timeout = 5
  18.  
  19.         if program:
  20.             self.set_program(program)
  21.         if input_values:
  22.             self.append_inputs(input_values)
  23.  
  24.     def reset(self):
  25.         self.program = self.original_program.copy()
  26.         self.pos = 0
  27.         self.rel_base = 0
  28.         self.outputs.clear()
  29.         self.input_deque.clear()
  30.  
  31.     def set_program(self, program):
  32.         try:
  33.             parsed_program = [int(c) for c in program.split(',')]
  34.         except AttributeError:
  35.             parsed_program = program
  36.         self.program = collections.defaultdict(int, zip(range(len(parsed_program)), parsed_program))
  37.         self.original_program = self.program.copy()
  38.  
  39.     def append_inputs(self, input_values):
  40.         try:
  41.             self.input_deque.extend(input_values)
  42.         except TypeError:
  43.             self.input_deque.append(input_values)
  44.         self.input_event.set()
  45.  
  46.     def set_output_receiver(self, output_receiver):
  47.         self.output_receiver = output_receiver
  48.  
  49.     def set_input_provider(self, input_provider):
  50.         self.input_provider = input_provider
  51.  
  52.     def set_event_timeout(self, timeout):
  53.         self.event_timeout = timeout
  54.  
  55.     OPCODE_NPARAMS = {
  56.         1: 3,
  57.         2: 3,
  58.         3: 1,
  59.         4: 1,
  60.         5: 2,
  61.         6: 2,
  62.         7: 3,
  63.         8: 3,
  64.         9: 1,
  65.         99: 0
  66.     }
  67.  
  68.     def execute(self):
  69.         while True:
  70.             instruction = self.program[self.pos]
  71.             opcode = instruction % 100
  72.             modes = instruction // 100
  73.             param_pointers = []
  74.             first_param = self.pos + 1
  75.            
  76.             for i in range(self.OPCODE_NPARAMS[opcode]):
  77.                 mode = modes % 10
  78.                 modes //= 10
  79.                 if mode == 0:
  80.                     param_pointers.append(self.program[first_param + i])
  81.                 elif mode == 1:
  82.                     param_pointers.append(first_param + i)
  83.                 elif mode == 2:
  84.                     param_pointers.append(self.program[first_param + i] + self.rel_base)
  85.                 else:
  86.                     raise Exception(f'Error: unknown mode {mode}')
  87.  
  88.             if opcode == 1:  # add
  89.                 p1, p2, out = param_pointers
  90.                 self.program[out] = self.program[p1] + self.program[p2]
  91.                 self.pos += 4
  92.  
  93.             elif opcode == 2:  # multiply
  94.                 p1, p2, out = param_pointers
  95.                 self.program[out] = self.program[p1] * self.program[p2]
  96.                 self.pos += 4
  97.  
  98.             elif opcode == 3:  # input
  99.                 if self.input_provider:
  100.                     # allow the provider to provide input
  101.                     # if you need to control input rate from providers, do it here
  102.                     self.input_provider.output_event.set()
  103.  
  104.                 try:
  105.                     self.program[param_pointers[0]] = self.input_deque.popleft()
  106.                 except IndexError:
  107.                     # if input_deque is empty, wait until it isn't
  108.                     self.input_event.clear()
  109.                     self.input_event.wait(timeout=self.event_timeout)
  110.                     self.program[param_pointers[0]] = self.input_deque.popleft()
  111.  
  112.                 self.pos += 2
  113.  
  114.             elif opcode == 4:  # output
  115.                 output = self.program[param_pointers[0]]
  116.  
  117.                 if self.output_receiver:
  118.                     # wait to provide input until allowed by receiver
  119.                     self.output_event.wait()
  120.                     self.output_receiver.append_inputs(output)
  121.                
  122.                 self.outputs.append(output)
  123.                 self.pos += 2
  124.  
  125.             elif opcode == 5:  # jump-if-true
  126.                 check, jump = param_pointers
  127.                 self.pos = self.program[jump] if self.program[check] else self.pos + 3
  128.  
  129.             elif opcode == 6:  # jump-if-false
  130.                 check, jump = param_pointers
  131.                 self.pos = self.program[jump] if not self.program[check] else self.pos + 3
  132.  
  133.             elif opcode == 7:  # less than
  134.                 p1, p2, out = param_pointers
  135.                 self.program[out] = (self.program[p1] < self.program[p2])
  136.                 self.pos += 4
  137.  
  138.             elif opcode == 8:  # equals
  139.                 p1, p2, out = param_pointers
  140.                 self.program[out] = (self.program[p1] == self.program[p2])
  141.                 self.pos += 4
  142.  
  143.             elif opcode == 9:  # relative base offset
  144.                 self.rel_base += self.program[param_pointers[0]]
  145.                 self.pos += 2
  146.  
  147.             elif opcode == 99:  # halt
  148.                 return self.outputs
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement