My big deal was making the Intcode computer fully backwards compatible with Day 5 and 7 as well as making it run for Day 9. (I haven't tried it with Day 2, though for some reason there's a part of my brain that thinks that is perhaps irreconcilable with that day).
I felt like the directions to this one were incredibly unclear. Should the program be able to write in the original instruction space or not? "Memory beyond the initial program starts with the value 0 and can be read or written like any other memory. (It is invalid to try to access memory at a negative address, though.)" What does "beyond" mean here? How do you differentiate between "beyond" memory and "any other memory," particularly if you can't "access memory at a negative space"? It was also unclear that the "beyond" memory was actually initialized with zeros. (I originally assumed that the program wouldn't attempt to access uninitialized space, but that ended up being proved wrong almost immediately.)
Still, this implementation served me pretty well:
fromenumimportEnumclassOperation(Enum):ADDITION=1MULTIPLICATION=2INPUT=3OUTPUT=4JUMP_IF_TRUE=5JUMP_IF_FALSE=6LESS_THAN=7EQUALS=8RELATIVE_BASE=9TERMINATION=99classMode(Enum):POSITION=0IMMEDIATE=1RELATIVE=2classInstruction:def__init__(self,opcode):# instruction: 1 is add, 2 is multiply, 3 is input, 4 is output, 99 is end
self.operation=Operation(_get_nth_digit(1,opcode)*10+_get_nth_digit(0,opcode))# mode: 0 is indirect, 1 is immediate
self.modes=list(map(Mode,[_get_nth_digit(2,opcode),_get_nth_digit(3,opcode),_get_nth_digit(4,opcode)]))def__str__(self):return"{}, {}".format(repr(self.operation),self.modes)classProgramState:def__init__(self,ops,output=None,address=0,memory={},rel_base=0,done=False):self.ops=ops# the instruction set
self.output=output# any previous output
self.address=address# index of next instruction to execute
self.memory=memory# the memory heap
self.rel_base=rel_base# the relative base from which to calculate relative addresses
self.done=done# flag to indicate whether this program has hit opcode 99
def__repr__(self):return"Last Output: {}, Rel Base: {}. Op Address: {}".format(self.output,self.rel_base,self.address)defrun(state,inp):return_run(state.ops,inp,state.address,state.output,state.memory,state.rel_base)def_run(ops,input,starting_addr,last_output,memory,rel_base):# start at the front of the inputs
input_idx=0# no output yet
output=last_output# assign to i for brevity
i=starting_addrwhileops[i]!=99:instruction=Instruction(ops[i])ifinstruction.operationisOperation.ADDITION:first=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)second=_get_resolved_arg(instruction,ops,memory,rel_base,i,2)destination=_get_resolved_position(instruction,ops,rel_base,i,3)_write(first+second,destination,ops,memory)i+=4elifinstruction.operationisOperation.MULTIPLICATION:first=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)second=_get_resolved_arg(instruction,ops,memory,rel_base,i,2)destination=_get_resolved_position(instruction,ops,rel_base,i,3)_write(first*second,destination,ops,memory)i+=4elifinstruction.operationisOperation.INPUT:destination=_get_resolved_position(instruction,ops,rel_base,i,1)_write(int(input[input_idx]),destination,ops,memory)input_idx+=1i+=2elifinstruction.operationisOperation.OUTPUT:output=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)i+=2returnProgramState(ops,output,i,memory,rel_base,False)elifinstruction.operationisOperation.JUMP_IF_TRUE:first=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)second=_get_resolved_arg(instruction,ops,memory,rel_base,i,2)iffirst!=0:i=secondelse:i+=3elifinstruction.operationisOperation.JUMP_IF_FALSE:first=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)second=_get_resolved_arg(instruction,ops,memory,rel_base,i,2)iffirst==0:i=secondelse:i+=3elifinstruction.operationisOperation.LESS_THAN:first=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)second=_get_resolved_arg(instruction,ops,memory,rel_base,i,2)destination=_get_resolved_position(instruction,ops,rel_base,i,3)_write(1iffirst<secondelse0,destination,ops,memory)i+=4elifinstruction.operationisOperation.EQUALS:first=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)second=_get_resolved_arg(instruction,ops,memory,rel_base,i,2)destination=_get_resolved_position(instruction,ops,rel_base,i,3)_write(1iffirst==secondelse0,destination,ops,memory)i+=4elifinstruction.operationisOperation.RELATIVE_BASE:rel_offset=_get_resolved_arg(instruction,ops,memory,rel_base,i,1)rel_base+=rel_offseti+=2returnProgramState(ops,output,i,{},rel_base,True)# Returns the number at the given position (0 being the rightmost)
def_get_nth_digit(n,number):returnnumber//10**n%10def_get_resolved_arg(instruction,ops,memory,rel_base,address,arg):# ops[i+1] if instruction.modes[0] is Mode.IMMEDIATE else ops[ops[i+1]]
mode=instruction.modes[arg-1]ifmodeisMode.IMMEDIATE:returnops[address+arg]final_addr=ops[address+arg]# Here, mode is POSITION or RELATIVE
# if RELATIVE add the relative base
ifmodeisMode.RELATIVE:final_addr+=rel_basereturnops[final_addr]iffinal_addr<len(ops)elsememory.get(final_addr,0)def_get_resolved_position(instruction,ops,rel_base,address,arg):# ops[i+1] if instruction.modes[0] is Mode.IMMEDIATE else ops[ops[i+1]]
mode=instruction.modes[arg-1]ifmodeisMode.POSITION:returnops[address+arg]elifmodeisMode.RELATIVE:returnops[address+arg]+rel_baseelse:print("Bonkers! Unhandled case")def_write(value,destination,ops,memory):ifdestination<len(ops):ops[destination]=valueelse:memory[destination]=value
And the driver program for Day 9:
fromintcodeimportProgramStatefromintcodeimportrunwithopen('day09.txt')asf:# split line into operation list
opsAsStrings=f.read().split(",")# turn them all into integers
ops=list(map(int,opsAsStrings))defboost(ops,inp):outputs=[]state=run(ProgramState(ops),[inp])whilenotstate.done:print(state.output)outputs.append(state.output)state=run(state,[])print(state.memory)returnoutputs# Part One
print("Part One: %s"%boost(ops,1))print("Part Two: %s"%boost(ops,2))
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
My big deal was making the Intcode computer fully backwards compatible with Day 5 and 7 as well as making it run for Day 9. (I haven't tried it with Day 2, though for some reason there's a part of my brain that thinks that is perhaps irreconcilable with that day).
I felt like the directions to this one were incredibly unclear. Should the program be able to write in the original instruction space or not? "Memory beyond the initial program starts with the value 0 and can be read or written like any other memory. (It is invalid to try to access memory at a negative address, though.)" What does "beyond" mean here? How do you differentiate between "beyond" memory and "any other memory," particularly if you can't "access memory at a negative space"? It was also unclear that the "beyond" memory was actually initialized with zeros. (I originally assumed that the program wouldn't attempt to access uninitialized space, but that ended up being proved wrong almost immediately.)
Still, this implementation served me pretty well:
And the driver program for Day 9: