Day 5 challenge (part 2)
This commit is contained in:
parent
31d53e2d9f
commit
e8bb936d05
@ -3,7 +3,7 @@ from collections import namedtuple
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG)
|
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.WARN)
|
||||||
|
|
||||||
|
|
||||||
def get_nth_digit(n, number):
|
def get_nth_digit(n, number):
|
||||||
@ -154,7 +154,7 @@ def run_input_program(filename):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# tests()
|
tests()
|
||||||
# a = [3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9]
|
# a = [3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, -1, 0, 1, 9]
|
||||||
# b = [3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1]
|
# b = [3, 3, 1105, -1, 9, 1101, 0, 0, 12, 4, 12, 99, 1]
|
||||||
|
|
||||||
|
192
day5/day52.py
Normal file
192
day5/day52.py
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
|
class Instruction:
|
||||||
|
code, argument_num = 0, 0
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def new_pc(self, intcode):
|
||||||
|
return intcode.pc + self.argument_num + 1
|
||||||
|
|
||||||
|
|
||||||
|
class PlusInstruction(Instruction):
|
||||||
|
code, argument_num = 1, 3
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
logging.debug(f"ADD {arguments[0].value} {arguments[1].value}")
|
||||||
|
intcode.set(arguments[2].address, arguments[0].value + arguments[1].value)
|
||||||
|
return self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class MultiplyInstruction(Instruction):
|
||||||
|
code, argument_num = 2, 3
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
logging.debug(f"MUL {arguments[0].value} {arguments[1].value}")
|
||||||
|
intcode.set(arguments[2].address, arguments[0].value * arguments[1].value)
|
||||||
|
return self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class InputInstruction(Instruction):
|
||||||
|
code, argument_num = 3, 1
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
intcode.set(arguments[0].address, intcode.get_input())
|
||||||
|
return self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class OutputInstruction(Instruction):
|
||||||
|
code, argument_num = 4, 1
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
intcode.output = arguments[0].value
|
||||||
|
return self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class JumpIfTrueInstruction(Instruction):
|
||||||
|
code, argument_num = 5, 2
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
logging.debug(f"JMPT {arguments[0].value} {arguments[1].value}")
|
||||||
|
return arguments[1].value if arguments[0].value != 0 else self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class JumpIfFalseInstruction(Instruction):
|
||||||
|
code, argument_num = 6, 2
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
logging.debug(f"JMPF {arguments[0].value} {arguments[1].value}")
|
||||||
|
return arguments[1].value if arguments[0].value == 0 else self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class LessThanInstruction(Instruction):
|
||||||
|
code, argument_num = 7, 3
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
logging.debug(f"LT {arguments[0].value} {arguments[1].value}")
|
||||||
|
intcode.set(arguments[2].address, int(arguments[0].value < arguments[1].value))
|
||||||
|
return self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class EqualsInstruction(Instruction):
|
||||||
|
code, argument_num = 8, 3
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
intcode.set(arguments[2].address, int(arguments[0].value == arguments[1].value))
|
||||||
|
return self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class RelativeBaseOffsetInstruction(Instruction):
|
||||||
|
code, argument_num = 9, 1
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
intcode.relative_base += arguments[0].value
|
||||||
|
return self.new_pc(intcode)
|
||||||
|
|
||||||
|
|
||||||
|
class HaltInstruction(Instruction):
|
||||||
|
code, argument_num = 99, 0
|
||||||
|
|
||||||
|
def execute(self, intcode, arguments):
|
||||||
|
intcode.halted = True
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Argument:
|
||||||
|
def __init__(self, value, address):
|
||||||
|
self.value = value
|
||||||
|
self.address = address
|
||||||
|
|
||||||
|
|
||||||
|
class IntCode:
|
||||||
|
def __init__(self, program, inputs=[], input_func=None):
|
||||||
|
self.program = program[:]
|
||||||
|
self.inputs = inputs[::-1]
|
||||||
|
self.input_func = input_func
|
||||||
|
self.relative_base = 0
|
||||||
|
self.memory = {}
|
||||||
|
self.output = None
|
||||||
|
self.halted = False
|
||||||
|
self.pc = 0
|
||||||
|
|
||||||
|
def _get_instruction(self, instruction_code):
|
||||||
|
return next(
|
||||||
|
cls for cls in Instruction.__subclasses__() if cls.code == instruction_code
|
||||||
|
)
|
||||||
|
|
||||||
|
def _parse_arguments(self, argument_num):
|
||||||
|
modes = str(self.program[self.pc]).zfill(5)[:3][::-1]
|
||||||
|
arguments = []
|
||||||
|
for i in range(argument_num):
|
||||||
|
value = self.program[self.pc + i + 1] + (
|
||||||
|
self.relative_base if modes[i] == "2" else 0
|
||||||
|
)
|
||||||
|
if modes[i] == "1":
|
||||||
|
arguments.append(Argument(value, value))
|
||||||
|
else:
|
||||||
|
arguments.append(
|
||||||
|
Argument(
|
||||||
|
self.program[value]
|
||||||
|
if value < len(self.program)
|
||||||
|
else self.memory.get(value, 0),
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return arguments
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.output = None
|
||||||
|
while not self.halted and self.output is None:
|
||||||
|
instruction = self._get_instruction(self.program[self.pc] % 100)
|
||||||
|
arguments = self._parse_arguments(instruction.argument_num)
|
||||||
|
self.pc = instruction().execute(self, arguments)
|
||||||
|
return self.output
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
last_output = None
|
||||||
|
while not self.halted:
|
||||||
|
output = self.run()
|
||||||
|
if not self.halted:
|
||||||
|
last_output = output
|
||||||
|
return last_output
|
||||||
|
|
||||||
|
def clone(self):
|
||||||
|
cloned = IntCode(self.program)
|
||||||
|
cloned.inputs = self.inputs[:]
|
||||||
|
cloned.input_func = self.input_func
|
||||||
|
cloned.relative_base = self.relative_base
|
||||||
|
cloned.memory = {key: value for key, value in self.memory.items()}
|
||||||
|
cloned.output = self.output
|
||||||
|
cloned.halted = self.halted
|
||||||
|
cloned.pc = self.pc
|
||||||
|
return cloned
|
||||||
|
|
||||||
|
def get(self, address):
|
||||||
|
return (
|
||||||
|
self.program[address]
|
||||||
|
if address < len(self.program)
|
||||||
|
else self.memory.get(value + self.relative_base, 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
def set(self, address, value):
|
||||||
|
target = self.program if address < len(self.program) else self.memory
|
||||||
|
target[address] = value
|
||||||
|
|
||||||
|
def input(self, value):
|
||||||
|
self.inputs = [value] + self.inputs
|
||||||
|
|
||||||
|
def get_input(self):
|
||||||
|
return self.inputs.pop() if self.inputs else self.input_func()
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
code = list(map(int, open(os.path.join(SCRIPT_DIR, "input.txt")).read().split(",")))
|
||||||
|
|
||||||
|
part2 = IntCode(code, [5]).execute()
|
||||||
|
print(part2)
|
Loading…
Reference in New Issue
Block a user