95 lines
3.3 KiB
Python
95 lines
3.3 KiB
Python
""" https://adventofcode.com/2019/day/9 """
|
|
|
|
class InvalidOpcode(Exception):
|
|
pass
|
|
|
|
class mylist(list):
|
|
def __getitem__(self, item):
|
|
try:
|
|
return super(mylist,self).__getitem__(item)
|
|
except IndexError as e:
|
|
if item < 0: raise IndexError()
|
|
super(mylist,self).extend([0]*(item + 1 - super(mylist,self).__len__()))
|
|
return super(mylist,self).__getitem__(item)
|
|
|
|
def __setitem__(self, idx, val):
|
|
try:
|
|
return super(mylist,self).__setitem__(idx,val)
|
|
except IndexError as e:
|
|
if idx < 0: raise IndexError()
|
|
super(mylist,self).extend([0]*(idx + 1 - super(mylist,self).__len__()))
|
|
return super(mylist,self).__setitem__(idx,val)
|
|
|
|
def readFile():
|
|
with open(f"{__file__.rstrip('code.py')}input.txt", "r") as f:
|
|
return [int(num) for num in f.readline().split(",")]
|
|
|
|
def getOutput(vals : list, input=0, base=0):
|
|
vals = mylist(vals)
|
|
i = 0
|
|
while 1:
|
|
opcode = (vals[i] % 100,
|
|
vals[i] // 100 % 10,
|
|
vals[i] // 1000 % 10,
|
|
vals[i] // 10000 % 10)
|
|
|
|
# 0 Parameter
|
|
if opcode[0] in [99]: # Termination
|
|
return vals
|
|
|
|
# 1 Parameter
|
|
elif opcode[0] in [3,4,9]:
|
|
a = vals[i+1] if not opcode[1] else i+1 if opcode[1] == 1 else base+vals[i+1]
|
|
if opcode[0] == 3: # Input
|
|
vals[a] = input
|
|
elif opcode[0] == 4: # Output
|
|
vals[0] = vals[a]
|
|
elif opcode[0] == 9: # Adjust Base
|
|
base += vals[a]
|
|
i += 2
|
|
|
|
# 2 Parameter
|
|
elif opcode[0] in [5,6]:
|
|
a = vals[i+1] if not opcode[1] else i+1 if opcode[1] == 1 else base+vals[i+1]
|
|
b = vals[i+2] if not opcode[2] else i+2 if opcode[2] == 1 else base+vals[i+2]
|
|
if opcode[0] == 5 and vals[a] != 0: # Jump-if-true
|
|
i = vals[b]
|
|
elif opcode[0] == 6 and vals[a] == 0: # Jump-if-false
|
|
i = vals[b]
|
|
else:
|
|
i += 3
|
|
|
|
# 3 Parameter
|
|
elif opcode[0] in [1,2,7,8]:
|
|
a = vals[i+1] if not opcode[1] else i+1 if opcode[1] == 1 else base+vals[i+1]
|
|
b = vals[i+2] if not opcode[2] else i+2 if opcode[2] == 1 else base+vals[i+2]
|
|
c = vals[i+3] if not opcode[3] else i+3 if opcode[3] == 1 else base+vals[i+3]
|
|
if opcode[0] == 1: # Addition
|
|
vals[c] = vals[a] + vals[b]
|
|
elif opcode[0] == 2: # Multiplication
|
|
vals[c] = vals[a] * vals[b]
|
|
elif opcode[0] == 7: # Less Than
|
|
vals[c] = int(vals[a] < vals[b])
|
|
elif opcode[0] == 8: # Equals
|
|
vals[c] = int(vals[a] == vals[b])
|
|
i += 4
|
|
|
|
else:
|
|
raise InvalidOpcode()
|
|
|
|
def part1(vals : list):
|
|
return getOutput(vals.copy(), input=1)[0]
|
|
|
|
def part2(vals : list):
|
|
return getOutput(vals.copy(), input=2)[0]
|
|
|
|
def test():
|
|
assert getOutput([104,1125899906842624,99])[0] == 1125899906842624
|
|
assert len(getOutput([109,19,204,-34,99], base=2000)) == 1986
|
|
assert len(str(getOutput([1102,34915192,34915192,7,4,7,99,0])[0])) == 16
|
|
|
|
if __name__ == "__main__":
|
|
test()
|
|
vals = readFile()
|
|
print(f"Part 1: {part1(vals)}")
|
|
print(f"Part 2: {part2(vals)}") |