Give position mode constants proper names, minor day 5 cleanup
parent
c0f9e18a64
commit
3dce44334d
|
@ -1,5 +1,5 @@
|
||||||
import sys
|
import sys
|
||||||
from typing import List, Tuple, Optional
|
from typing import Iterable, List, Tuple, Optional
|
||||||
|
|
||||||
|
|
||||||
# Halt indicates that the assembled program should terminate
|
# Halt indicates that the assembled program should terminate
|
||||||
|
@ -7,6 +7,7 @@ class Halt(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Operation represents an operation that the intcode computer should do
|
||||||
class Operation:
|
class Operation:
|
||||||
OPCODE_TERMINATE = 99
|
OPCODE_TERMINATE = 99
|
||||||
OPCODE_ADD = 1
|
OPCODE_ADD = 1
|
||||||
|
@ -17,19 +18,19 @@ class Operation:
|
||||||
OPCODE_JUMP_IF_FALSE = 6
|
OPCODE_JUMP_IF_FALSE = 6
|
||||||
OPCODE_LESS_THAN = 7
|
OPCODE_LESS_THAN = 7
|
||||||
OPCODE_EQUALS = 8
|
OPCODE_EQUALS = 8
|
||||||
MODE_PARAMETER = 0
|
MODE_POSITION = 0
|
||||||
MODE_IMMEDIATE = 1
|
MODE_IMMEDIATE = 1
|
||||||
OPCODE__ALLS = (OPCODE_TERMINATE, OPCODE_ADD, OPCODE_MULTIPLY, OPCODE_INPUT, OPCODE_OUTPUT,
|
ALL_OPCODES = (OPCODE_TERMINATE, OPCODE_ADD, OPCODE_MULTIPLY, OPCODE_INPUT, OPCODE_OUTPUT,
|
||||||
OPCODE_JUMP_IF_TRUE, OPCODE_JUMP_IF_FALSE, OPCODE_LESS_THAN, OPCODE_EQUALS)
|
OPCODE_JUMP_IF_TRUE, OPCODE_JUMP_IF_FALSE, OPCODE_LESS_THAN, OPCODE_EQUALS)
|
||||||
|
|
||||||
def __init__(self, instruction: int):
|
def __init__(self, instruction: int):
|
||||||
# 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.OPCODE__ALLS:
|
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)
|
||||||
|
|
||||||
def _extract_parameter_modes(self, raw_modes) -> Tuple[int]:
|
def _extract_parameter_modes(self, raw_modes) -> Tuple[int, ...]:
|
||||||
PARAMETER_COUNTS = {
|
PARAMETER_COUNTS = {
|
||||||
Operation.OPCODE_TERMINATE: 0,
|
Operation.OPCODE_TERMINATE: 0,
|
||||||
Operation.OPCODE_ADD: 3,
|
Operation.OPCODE_ADD: 3,
|
||||||
|
@ -41,11 +42,12 @@ class Operation:
|
||||||
Operation.OPCODE_LESS_THAN: 3,
|
Operation.OPCODE_LESS_THAN: 3,
|
||||||
Operation.OPCODE_EQUALS: 3,
|
Operation.OPCODE_EQUALS: 3,
|
||||||
}
|
}
|
||||||
|
# Opcodes that write to memory as their last parameter
|
||||||
MEMORY_OPCODES = (Operation.OPCODE_ADD, Operation.OPCODE_MULTIPLY, Operation.OPCODE_INPUT,
|
MEMORY_OPCODES = (Operation.OPCODE_ADD, Operation.OPCODE_MULTIPLY, Operation.OPCODE_INPUT,
|
||||||
Operation.OPCODE_LESS_THAN, Operation.OPCODE_EQUALS)
|
Operation.OPCODE_LESS_THAN, Operation.OPCODE_EQUALS)
|
||||||
|
|
||||||
num_parameters = PARAMETER_COUNTS[self.opcode]
|
num_parameters = PARAMETER_COUNTS[self.opcode]
|
||||||
modes = [Operation.MODE_PARAMETER for i in range(num_parameters)]
|
modes = [Operation.MODE_POSITION for i in range(num_parameters)]
|
||||||
mode_str = str(raw_modes)
|
mode_str = str(raw_modes)
|
||||||
# Iterate over the modes digits backwards, assigning them to the parameter list until we exhaust the modes
|
# Iterate over the modes digits backwards, assigning them to the parameter list until we exhaust the modes
|
||||||
# The rest must be leading zeroes
|
# The rest must be leading zeroes
|
||||||
|
@ -53,7 +55,8 @@ class Operation:
|
||||||
modes[mode_index] = int(digit)
|
modes[mode_index] = int(digit)
|
||||||
|
|
||||||
# The last argument (the address parameter) must always be in immediate mode
|
# The last argument (the address parameter) must always be in immediate mode
|
||||||
|
# The problem statement is misleading in this regard. You do NOT want to get an address to store the value
|
||||||
|
# at from another address.
|
||||||
if self.opcode in MEMORY_OPCODES:
|
if self.opcode in MEMORY_OPCODES:
|
||||||
modes[-1] = Operation.MODE_IMMEDIATE
|
modes[-1] = Operation.MODE_IMMEDIATE
|
||||||
|
|
||||||
|
@ -61,7 +64,7 @@ class Operation:
|
||||||
|
|
||||||
# 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
|
# Returns the address that the instruction pointer should become
|
||||||
def run(self, memory: List[int], instruction_pointer: int, program_input=None) -> int:
|
def run(self, memory: List[int], 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,
|
||||||
|
@ -80,7 +83,7 @@ class Operation:
|
||||||
# Add 1 to move past the opcode itself
|
# Add 1 to move past the opcode itself
|
||||||
pointer = instruction_pointer + i + 1
|
pointer = instruction_pointer + i + 1
|
||||||
arg = memory[pointer]
|
arg = memory[pointer]
|
||||||
if mode == Operation.MODE_PARAMETER:
|
if mode == Operation.MODE_POSITION:
|
||||||
arg = memory[arg]
|
arg = memory[arg]
|
||||||
elif mode != Operation.MODE_IMMEDIATE:
|
elif mode != Operation.MODE_IMMEDIATE:
|
||||||
raise ValueError(f"Invalid parameter mode {mode}")
|
raise ValueError(f"Invalid parameter mode {mode}")
|
||||||
|
@ -88,10 +91,10 @@ class Operation:
|
||||||
args.append(arg)
|
args.append(arg)
|
||||||
|
|
||||||
func = OPERATION_FUNCS[self.opcode]
|
func = OPERATION_FUNCS[self.opcode]
|
||||||
if program_input is not None:
|
if program_input is None:
|
||||||
jump_addr = func(memory, program_input, *args)
|
|
||||||
else:
|
|
||||||
jump_addr = func(memory, *args)
|
jump_addr = func(memory, *args)
|
||||||
|
else:
|
||||||
|
jump_addr = func(memory, program_input, *args)
|
||||||
|
|
||||||
if jump_addr is not None:
|
if jump_addr is not None:
|
||||||
return jump_addr
|
return jump_addr
|
||||||
|
@ -169,5 +172,7 @@ if __name__ == "__main__":
|
||||||
with open(sys.argv[1]) as f:
|
with open(sys.argv[1]) as f:
|
||||||
inputs = [int(item) for item in f.read().rstrip().split(",")]
|
inputs = [int(item) for item in f.read().rstrip().split(",")]
|
||||||
|
|
||||||
|
print("PART 1")
|
||||||
part1(inputs)
|
part1(inputs)
|
||||||
|
print("PART 2")
|
||||||
part2(inputs)
|
part2(inputs)
|
||||||
|
|
Loading…
Reference in New Issue