Minor intcode cleanup

master
Nick Krichevsky 2019-12-11 01:13:52 -05:00
parent 2e63f5b59a
commit 1342fb40e6
2 changed files with 81 additions and 19 deletions

View File

@ -1,5 +1,5 @@
--- day9intcode.py 2019-12-11 01:02:10.952864966 -0500 --- day9intcode.py 2019-12-11 01:02:10.952864966 -0500
+++ day11intcode.py 2019-12-11 01:02:34.308613523 -0500 +++ day11intcode.py 2019-12-11 01:14:04.585182158 -0500
@@ -1,7 +1,6 @@ @@ -1,7 +1,6 @@
import collections import collections
import sys import sys
@ -9,7 +9,52 @@
# Halt indicates that the assembled program should terminate # Halt indicates that the assembled program should terminate
class Halt(Exception): class Halt(Exception):
@@ -136,7 +135,6 @@ @@ -35,14 +34,14 @@
# Opcodes that write to memory as their last parameter
MEMORY_OPCODES = (OPCODE_ADD, OPCODE_MULTIPLY, OPCODE_INPUT, OPCODE_LESS_THAN, OPCODE_EQUALS)
- def __init__(self, instruction: int):
+ def __init__(self, instruction: int, rel_base: int = 0):
# The opcode is the first two digits of the number, the rest are parameter modes
self.opcode: int = instruction % 100
if self.opcode not in Operation.ALL_OPCODES:
raise ValueError(f"Bad opcode: {self.opcode}")
self.modes: Tuple[int, ...] = self._extract_parameter_modes(instruction//100)
self.output = None
- self.rel_base = 0
+ self.rel_base = rel_base
def _extract_parameter_modes(self, raw_modes) -> Tuple[int, ...]:
PARAMETER_COUNTS = {
@@ -69,8 +68,8 @@
return tuple(modes)
# Run the given operation, starting at the given instruction pointer
- # Returns the address that the instruction pointer should become, the relative base, followed by the output of the operation, if any
- def run(self, memory: Memory, instruction_pointer: int, rel_base: int = 0, program_input: Optional[int] = None) -> Tuple[int, int, Optional[int]]:
+ # Returns the address that the instruction pointer should become
+ def run(self, memory: Memory, instruction_pointer: int, program_input: Optional[int] = None) -> int:
OPERATION_FUNCS = {
# nop for terminate
Operation.OPCODE_TERMINATE: Operation.terminate,
@@ -87,7 +86,6 @@
# Reset the output and rel base of a previous run
self.output = None
- self.rel_base = rel_base
args = []
for i, mode in enumerate(self.modes):
@@ -120,7 +118,7 @@
if jump_addr is not None:
out_addr = jump_addr
- return out_addr, self.rel_base, self.output
+ return out_addr
def terminate(self, memory: Memory) -> None:
raise Halt("catch fire")
@@ -136,7 +134,6 @@
def output(self, memory: Memory, value: int) -> None: def output(self, memory: Memory, value: int) -> None:
self.output = value self.output = value
@ -17,8 +62,14 @@
def jump_if_true(self, memory: Memory, test_value: int, new_instruction_pointer: int) -> Optional[int]: def jump_if_true(self, memory: Memory, test_value: int, new_instruction_pointer: int) -> Optional[int]:
return new_instruction_pointer if test_value != 0 else None return new_instruction_pointer if test_value != 0 else None
@@ -154,13 +152,13 @@ @@ -150,31 +147,33 @@
self.rel_base += rel_base def equals(self, memory: Memory, a: int, b: int, loc: int) -> None:
memory[loc] = int(a == b)
- def set_rel_base(self, memory: Memory, rel_base: int) -> None:
- self.rel_base += rel_base
+ def set_rel_base(self, memory: Memory, base_delta: int) -> None:
+ self.rel_base += base_delta
-# Executes the program, returning the instruction pointer to continue at (if the program paused) and a list of all -# Executes the program, returning the instruction pointer to continue at (if the program paused) and a list of all
@ -26,7 +77,7 @@
-def execute_program(memory: Memory, program_inputs: List[int], initial_instruction_pointer: int = 0) -> (Optional[int], List[int]): -def execute_program(memory: Memory, program_inputs: List[int], initial_instruction_pointer: int = 0) -> (Optional[int], List[int]):
+# Executes the program, returning the instruction pointer to continue at (if the program paused), the relative base, +# Executes the program, returning the instruction pointer to continue at (if the program paused), the relative base,
+# and a list of all outputs that occurred during the program's execution +# and a list of all outputs that occurred during the program's execution
+def execute_program(memory: Memory, program_inputs: List[int], initial_instruction_pointer: int = 0, initial_rel_base: int = 0) -> (Optional[int], int, List[int]): +def execute_program(memory: Memory, program_inputs: List[int], initial_instruction_pointer: int = 0, initial_rel_base: int = 0) -> Tuple[Optional[int], int, List[int]]:
i = initial_instruction_pointer i = initial_instruction_pointer
input_cursor = 0 input_cursor = 0
- rel_base = 0 - rel_base = 0
@ -34,8 +85,10 @@
+ rel_base = initial_rel_base + rel_base = initial_rel_base
# Go up to the maximum address, not the number of addresses # Go up to the maximum address, not the number of addresses
while i < max(memory.keys()): while i < max(memory.keys()):
operation = Operation(memory[i]) - operation = Operation(memory[i])
@@ -169,7 +167,7 @@ + operation = Operation(memory[i], rel_base)
program_input = None
# If we're looking for input
if operation.opcode == Operation.OPCODE_INPUT: if operation.opcode == Operation.OPCODE_INPUT:
# If we are out of input, don't fail out, but rather just pause execution # If we are out of input, don't fail out, but rather just pause execution
if input_cursor >= len(program_inputs): if input_cursor >= len(program_inputs):
@ -44,7 +97,15 @@
program_input = program_inputs[input_cursor] program_input = program_inputs[input_cursor]
input_cursor += 1 input_cursor += 1
@@ -182,4 +180,4 @@ try:
- i, rel_base, output = operation.run(memory, i, rel_base, program_input)
+ i = operation.run(memory, i, program_input)
+ output = operation.output
+ rel_base = operation.rel_base
except Halt:
break
@@ -182,4 +181,4 @@
outputs.append(output) outputs.append(output)
# The program is finished, and we are saying there is no instruction pointer # The program is finished, and we are saying there is no instruction pointer

View File

@ -34,14 +34,14 @@ class Operation:
# Opcodes that write to memory as their last parameter # Opcodes that write to memory as their last parameter
MEMORY_OPCODES = (OPCODE_ADD, OPCODE_MULTIPLY, OPCODE_INPUT, OPCODE_LESS_THAN, OPCODE_EQUALS) MEMORY_OPCODES = (OPCODE_ADD, OPCODE_MULTIPLY, OPCODE_INPUT, OPCODE_LESS_THAN, OPCODE_EQUALS)
def __init__(self, instruction: int): def __init__(self, instruction: int, rel_base: int = 0):
# The opcode is the first two digits of the number, the rest are parameter modes # The opcode is the first two digits of the number, the rest are parameter modes
self.opcode: int = instruction % 100 self.opcode: int = instruction % 100
if self.opcode not in Operation.ALL_OPCODES: if self.opcode not in Operation.ALL_OPCODES:
raise ValueError(f"Bad opcode: {self.opcode}") raise ValueError(f"Bad opcode: {self.opcode}")
self.modes: Tuple[int, ...] = self._extract_parameter_modes(instruction//100) self.modes: Tuple[int, ...] = self._extract_parameter_modes(instruction//100)
self.output = None self.output = None
self.rel_base = 0 self.rel_base = rel_base
def _extract_parameter_modes(self, raw_modes) -> Tuple[int, ...]: def _extract_parameter_modes(self, raw_modes) -> Tuple[int, ...]:
PARAMETER_COUNTS = { PARAMETER_COUNTS = {
@ -68,8 +68,8 @@ class Operation:
return tuple(modes) return tuple(modes)
# Run the given operation, starting at the given instruction pointer # Run the given operation, starting at the given instruction pointer
# Returns the address that the instruction pointer should become, the relative base, followed by the output of the operation, if any # Returns the address that the instruction pointer should become
def run(self, memory: Memory, instruction_pointer: int, rel_base: int = 0, program_input: Optional[int] = None) -> Tuple[int, int, Optional[int]]: def run(self, memory: Memory, instruction_pointer: int, program_input: Optional[int] = None) -> int:
OPERATION_FUNCS = { OPERATION_FUNCS = {
# nop for terminate # nop for terminate
Operation.OPCODE_TERMINATE: Operation.terminate, Operation.OPCODE_TERMINATE: Operation.terminate,
@ -86,7 +86,6 @@ class Operation:
# Reset the output and rel base of a previous run # Reset the output and rel base of a previous run
self.output = None self.output = None
self.rel_base = rel_base
args = [] args = []
for i, mode in enumerate(self.modes): for i, mode in enumerate(self.modes):
@ -119,7 +118,7 @@ class Operation:
if jump_addr is not None: if jump_addr is not None:
out_addr = jump_addr out_addr = jump_addr
return out_addr, self.rel_base, self.output return out_addr
def terminate(self, memory: Memory) -> None: def terminate(self, memory: Memory) -> None:
raise Halt("catch fire") raise Halt("catch fire")
@ -148,20 +147,20 @@ class Operation:
def equals(self, memory: Memory, a: int, b: int, loc: int) -> None: def equals(self, memory: Memory, a: int, b: int, loc: int) -> None:
memory[loc] = int(a == b) memory[loc] = int(a == b)
def set_rel_base(self, memory: Memory, rel_base: int) -> None: def set_rel_base(self, memory: Memory, base_delta: int) -> None:
self.rel_base += rel_base self.rel_base += base_delta
# Executes the program, returning the instruction pointer to continue at (if the program paused), the relative base, # Executes the program, returning the instruction pointer to continue at (if the program paused), the relative base,
# and a list of all outputs that occurred during the program's execution # and a list of all outputs that occurred during the program's execution
def execute_program(memory: Memory, program_inputs: List[int], initial_instruction_pointer: int = 0, initial_rel_base: int = 0) -> (Optional[int], int, List[int]): def execute_program(memory: Memory, program_inputs: List[int], initial_instruction_pointer: int = 0, initial_rel_base: int = 0) -> Tuple[Optional[int], int, List[int]]:
i = initial_instruction_pointer i = initial_instruction_pointer
input_cursor = 0 input_cursor = 0
outputs = [] outputs = []
rel_base = initial_rel_base rel_base = initial_rel_base
# Go up to the maximum address, not the number of addresses # Go up to the maximum address, not the number of addresses
while i < max(memory.keys()): while i < max(memory.keys()):
operation = Operation(memory[i]) operation = Operation(memory[i], rel_base)
program_input = None program_input = None
# If we're looking for input # If we're looking for input
if operation.opcode == Operation.OPCODE_INPUT: if operation.opcode == Operation.OPCODE_INPUT:
@ -172,7 +171,9 @@ def execute_program(memory: Memory, program_inputs: List[int], initial_instructi
input_cursor += 1 input_cursor += 1
try: try:
i, rel_base, output = operation.run(memory, i, rel_base, program_input) i = operation.run(memory, i, program_input)
output = operation.output
rel_base = operation.rel_base
except Halt: except Halt:
break break