Minor intcode cleanup
parent
2e63f5b59a
commit
1342fb40e6
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue