Add diff in intcode since day 7
This commit is contained in:
parent
c3365f2faf
commit
2f607139de
189
day9/py/intcode_changes_since_day_7.diff
Normal file
189
day9/py/intcode_changes_since_day_7.diff
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
--- day7intcode.py 2019-12-09 01:30:05.907769133 -0500
|
||||||
|
+++ day9intcode.py 2019-12-09 01:29:48.539936730 -0500
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
+import collections
|
||||||
|
import sys
|
||||||
|
-import itertools
|
||||||
|
from typing import List, Tuple, Optional
|
||||||
|
|
||||||
|
|
||||||
|
@@ -8,6 +8,13 @@
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
+class Memory(collections.OrderedDict):
|
||||||
|
+ def __missing__(self, address):
|
||||||
|
+ if address < 0:
|
||||||
|
+ raise KeyError("Address cannot be < 0")
|
||||||
|
+ return 0
|
||||||
|
+
|
||||||
|
+
|
||||||
|
# Operation represents an operation that the intcode computer should do
|
||||||
|
class Operation:
|
||||||
|
OPCODE_TERMINATE = 99
|
||||||
|
@@ -19,10 +26,14 @@
|
||||||
|
OPCODE_JUMP_IF_FALSE = 6
|
||||||
|
OPCODE_LESS_THAN = 7
|
||||||
|
OPCODE_EQUALS = 8
|
||||||
|
+ OPCODE_SET_REL_BASE = 9
|
||||||
|
MODE_POSITION = 0
|
||||||
|
MODE_IMMEDIATE = 1
|
||||||
|
+ MODE_RELATIVE = 2
|
||||||
|
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, OPCODE_SET_REL_BASE)
|
||||||
|
+ # 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):
|
||||||
|
# The opcode is the first two digits of the number, the rest are parameter modes
|
||||||
|
@@ -31,6 +42,7 @@
|
||||||
|
raise ValueError(f"Bad opcode: {self.opcode}")
|
||||||
|
self.modes: Tuple[int, ...] = self._extract_parameter_modes(instruction//100)
|
||||||
|
self.output = None
|
||||||
|
+ self.rel_base = 0
|
||||||
|
|
||||||
|
def _extract_parameter_modes(self, raw_modes) -> Tuple[int, ...]:
|
||||||
|
PARAMETER_COUNTS = {
|
||||||
|
@@ -43,10 +55,8 @@
|
||||||
|
Operation.OPCODE_JUMP_IF_FALSE: 2,
|
||||||
|
Operation.OPCODE_LESS_THAN: 3,
|
||||||
|
Operation.OPCODE_EQUALS: 3,
|
||||||
|
+ Operation.OPCODE_SET_REL_BASE: 1,
|
||||||
|
}
|
||||||
|
- # 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_POSITION for i in range(num_parameters)]
|
||||||
|
@@ -56,17 +66,11 @@
|
||||||
|
for mode_index, digit in zip(range(num_parameters), reversed(mode_str)):
|
||||||
|
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
|
||||||
|
-
|
||||||
|
return tuple(modes)
|
||||||
|
|
||||||
|
# Run the given operation, starting at the given instruction pointer
|
||||||
|
- # Returns the address that the instruction pointer should become, followed by the output of the operation, if any
|
||||||
|
- def run(self, memory: List[int], instruction_pointer: int, program_input: Optional[int] = None) -> Tuple[int, Optional[int]]:
|
||||||
|
+ # 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]]:
|
||||||
|
OPERATION_FUNCS = {
|
||||||
|
# nop for terminate
|
||||||
|
Operation.OPCODE_TERMINATE: Operation.terminate,
|
||||||
|
@@ -77,19 +81,30 @@
|
||||||
|
Operation.OPCODE_JUMP_IF_TRUE: Operation.jump_if_true,
|
||||||
|
Operation.OPCODE_JUMP_IF_FALSE: Operation.jump_if_false,
|
||||||
|
Operation.OPCODE_LESS_THAN: Operation.less_than,
|
||||||
|
- Operation.OPCODE_EQUALS: Operation.equals
|
||||||
|
+ Operation.OPCODE_EQUALS: Operation.equals,
|
||||||
|
+ Operation.OPCODE_SET_REL_BASE: Operation.set_rel_base
|
||||||
|
}
|
||||||
|
|
||||||
|
- # Reset the output of a previous run
|
||||||
|
+ # 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):
|
||||||
|
# Add 1 to move past the opcode itself
|
||||||
|
pointer = instruction_pointer + i + 1
|
||||||
|
arg = memory[pointer]
|
||||||
|
- if mode == Operation.MODE_POSITION:
|
||||||
|
+ # The last argument (the address parameter) must always act as an immediate
|
||||||
|
+ # 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 mode != self.MODE_IMMEDIATE and i == len(self.modes) - 1 and self.opcode in Operation.MEMORY_OPCODES:
|
||||||
|
+ if mode == Operation.MODE_RELATIVE:
|
||||||
|
+ arg = self.rel_base + arg
|
||||||
|
+ # Position mode is already handled since it would be arg = arg here.
|
||||||
|
+ elif mode == Operation.MODE_POSITION:
|
||||||
|
arg = memory[arg]
|
||||||
|
+ elif mode == Operation.MODE_RELATIVE:
|
||||||
|
+ arg = memory[self.rel_base + arg]
|
||||||
|
elif mode != Operation.MODE_IMMEDIATE:
|
||||||
|
raise ValueError(f"Invalid parameter mode {mode}")
|
||||||
|
|
||||||
|
@@ -101,47 +116,53 @@
|
||||||
|
else:
|
||||||
|
jump_addr = func(self, memory, program_input, *args)
|
||||||
|
|
||||||
|
+ out_addr = instruction_pointer + len(self.modes) + 1
|
||||||
|
if jump_addr is not None:
|
||||||
|
- return jump_addr, self.output
|
||||||
|
+ out_addr = jump_addr
|
||||||
|
|
||||||
|
- return instruction_pointer + len(self.modes) + 1, self.output
|
||||||
|
+ return out_addr, self.rel_base, self.output
|
||||||
|
|
||||||
|
- def terminate(self, memory: List[int]) -> None:
|
||||||
|
+ def terminate(self, memory: Memory) -> None:
|
||||||
|
raise Halt("catch fire")
|
||||||
|
|
||||||
|
- def add(self, memory: List[int], a: int, b: int, loc: int) -> None:
|
||||||
|
+ def add(self, memory: Memory, a: int, b: int, loc: int) -> None:
|
||||||
|
memory[loc] = a + b
|
||||||
|
|
||||||
|
- def multiply(self, memory: List[int], a: int, b: int, loc: int) -> None:
|
||||||
|
+ def multiply(self, memory: Memory, a: int, b: int, loc: int) -> None:
|
||||||
|
memory[loc] = a * b
|
||||||
|
|
||||||
|
- def input(self, memory: List[int], program_input: int, loc: int) -> None:
|
||||||
|
+ def input(self, memory: Memory, program_input: int, loc: int) -> None:
|
||||||
|
memory[loc] = program_input
|
||||||
|
|
||||||
|
- def output(self, memory: List[int], value: int) -> None:
|
||||||
|
+ def output(self, memory: Memory, value: int) -> None:
|
||||||
|
self.output = value
|
||||||
|
print("OUTPUT:", value)
|
||||||
|
|
||||||
|
- def jump_if_true(self, memory: List[int], 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
|
||||||
|
|
||||||
|
- def jump_if_false(self, memory: List[int], test_value: int, new_instruction_pointer: int) -> Optional[int]:
|
||||||
|
+ def jump_if_false(self, memory: Memory, test_value: int, new_instruction_pointer: int) -> Optional[int]:
|
||||||
|
return new_instruction_pointer if test_value == 0 else None
|
||||||
|
|
||||||
|
- def less_than(self, memory: List[int], a: int, b: int, loc: int):
|
||||||
|
+ def less_than(self, memory: Memory, a: int, b: int, loc: int) -> None:
|
||||||
|
memory[loc] = int(a < b)
|
||||||
|
|
||||||
|
- def equals(self, memory: List[int], a: int, b: int, loc: int):
|
||||||
|
+ 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
|
||||||
|
+
|
||||||
|
|
||||||
|
# Executes the program, returning the instruction pointer to continue at (if the program paused) and a list of all
|
||||||
|
# outputs that occurred during the program's execution
|
||||||
|
-def execute_program(memory: List[int], 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]):
|
||||||
|
i = initial_instruction_pointer
|
||||||
|
input_cursor = 0
|
||||||
|
+ rel_base = 0
|
||||||
|
outputs = []
|
||||||
|
- while i < len(memory):
|
||||||
|
+ # Go up to the maximum address, not the number of addresses
|
||||||
|
+ while i < max(memory.keys()):
|
||||||
|
operation = Operation(memory[i])
|
||||||
|
program_input = None
|
||||||
|
# If we're looking for input
|
||||||
|
@@ -153,7 +174,7 @@
|
||||||
|
input_cursor += 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
- i, output = operation.run(memory, i, program_input)
|
||||||
|
+ i, rel_base, output = operation.run(memory, i, rel_base, program_input)
|
||||||
|
except Halt:
|
||||||
|
break
|
||||||
|
|
Loading…
Reference in a new issue