From 3dce44334d4d6d1d00e4875c4cbec07ad56fac39 Mon Sep 17 00:00:00 2001 From: Nick Krichevsky Date: Thu, 5 Dec 2019 01:56:18 -0500 Subject: [PATCH] Give position mode constants proper names, minor day 5 cleanup --- day5/py/main.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/day5/py/main.py b/day5/py/main.py index a00dda8..df1c873 100644 --- a/day5/py/main.py +++ b/day5/py/main.py @@ -1,5 +1,5 @@ import sys -from typing import List, Tuple, Optional +from typing import Iterable, List, Tuple, Optional # Halt indicates that the assembled program should terminate @@ -7,6 +7,7 @@ class Halt(Exception): pass +# Operation represents an operation that the intcode computer should do class Operation: OPCODE_TERMINATE = 99 OPCODE_ADD = 1 @@ -17,19 +18,19 @@ class Operation: OPCODE_JUMP_IF_FALSE = 6 OPCODE_LESS_THAN = 7 OPCODE_EQUALS = 8 - MODE_PARAMETER = 0 + MODE_POSITION = 0 MODE_IMMEDIATE = 1 - OPCODE__ALLS = (OPCODE_TERMINATE, OPCODE_ADD, OPCODE_MULTIPLY, OPCODE_INPUT, OPCODE_OUTPUT, - OPCODE_JUMP_IF_TRUE, OPCODE_JUMP_IF_FALSE, OPCODE_LESS_THAN, OPCODE_EQUALS) + 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) def __init__(self, instruction: int): # 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.OPCODE__ALLS: + 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.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 = { Operation.OPCODE_TERMINATE: 0, Operation.OPCODE_ADD: 3, @@ -41,11 +42,12 @@ class Operation: Operation.OPCODE_LESS_THAN: 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, Operation.OPCODE_LESS_THAN, Operation.OPCODE_EQUALS) 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) # Iterate over the modes digits backwards, assigning them to the parameter list until we exhaust the modes # The rest must be leading zeroes @@ -53,7 +55,8 @@ class Operation: modes[mode_index] = int(digit) # 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: modes[-1] = Operation.MODE_IMMEDIATE @@ -61,7 +64,7 @@ class Operation: # Run the given operation, starting at the given instruction pointer # 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 = { # nop for terminate Operation.OPCODE_TERMINATE: Operation.terminate, @@ -80,7 +83,7 @@ class Operation: # Add 1 to move past the opcode itself pointer = instruction_pointer + i + 1 arg = memory[pointer] - if mode == Operation.MODE_PARAMETER: + if mode == Operation.MODE_POSITION: arg = memory[arg] elif mode != Operation.MODE_IMMEDIATE: raise ValueError(f"Invalid parameter mode {mode}") @@ -88,10 +91,10 @@ class Operation: args.append(arg) func = OPERATION_FUNCS[self.opcode] - if program_input is not None: - jump_addr = func(memory, program_input, *args) - else: + if program_input is None: jump_addr = func(memory, *args) + else: + jump_addr = func(memory, program_input, *args) if jump_addr is not None: return jump_addr @@ -169,5 +172,7 @@ if __name__ == "__main__": with open(sys.argv[1]) as f: inputs = [int(item) for item in f.read().rstrip().split(",")] + print("PART 1") part1(inputs) + print("PART 2") part2(inputs)