Ryan is an engineer in the Sacramento Area with a focus in Python, Ruby, and Rust. Bash/Python Exercism mentor. Coding, physics, calculus, music, woodworking. Looking for work!
Had a rough time hunting down some issues that caused all of the available test cases to pass but failed my puzzle input. Turns out I should have been using "x % 10" to get the one's digit, not "x % 3" like I had.
Also, I feel like the specification for how opcode 3 (read input) works with this new relative parameter mode wasn't made super clear. But it worked out in the end. Here's my rust solution:
/// Day 9: Sensor Boost/// /// Boost sensors with relative Intcode parameters.usestd::fs;usecrate::intcode::IntcodeInterpreter;/// Parses the input. Expects a single line of integers separated by/// commasfnparse_input()->Vec<isize>{lettext:String=fs::read_to_string("data/day9.txt").unwrap();letcleaned=text.trim();cleaned.split(",").map(|c|c.parse().unwrap()).collect()}pubfnrun(){letnumbers=parse_input();letmuta=IntcodeInterpreter::new(numbers);a.push_input(2);a.run();println!("Result: {}",a.shift_output());}
And my Intcode Interpreter:
usestd::io;usestd::collections::HashMap;/// An Intcode Interpreter is a simple virtual machine that uses opcodes/// to modify its internal memorypubstructIntcodeInterpreter{memory:HashMap<usize,isize>,in_buffer:Vec<isize>,out_buffer:Vec<isize>,ip:usize,relative_base:isize,}implIntcodeInterpreter{pubfnnew(numbers:Vec<isize>)->Self{letmutmemory:HashMap<usize,isize>=HashMap::new();for(ind,num)innumbers.iter().enumerate(){memory.insert(ind,*num);}Self{memory,in_buffer:Vec::new(),out_buffer:Vec::new(),ip:0,relative_base:0,}}/// Sets a memory address to a valuepubfnset(&mutself,position:usize,value:isize){self.memory.insert(position,value);}/// Reads from a memory addresspubfnget(&mutself,position:usize)->isize{*self.memory.entry(position).or_default()}/// Shows the memory for debuggingpubfnprint(&self){println!("{:?}",self.memory);}/// Get the current instructionpubfncurrent_instruction(&mutself)->isize{self.get(self.ip)%100}/// Add a value to the input queuepubfnpush_input(&mutself,value:isize){self.in_buffer.push(value);ifself.current_instruction()==98{self.memory.insert(self.ip,self.memory[&self.ip]-95);// Return the instruction to// a 3 while maintaining// argtype values}}pubfncount_output(&self)->usize{self.out_buffer.len()}/// Pop a value off the output queuepubfnshift_output(&mutself)->isize{ifself.out_buffer.is_empty(){panic!("Shift from empty out buffer!");}self.out_buffer.remove(0)}/// Runs the program in memory until the stopcode (99) is reached/// /// All new ops should have their own method./// They take no rust args, but read in args as needed and/// shift the instruction pointer when they're done./// Steps should be the number of args used + 1 for the opcodepubfnrun(&mutself){loop{matchself.current_instruction(){1=>self.op1(),2=>self.op2(),3=>self.op3(),4=>self.op4(),5=>self.op5(),6=>self.op6(),7=>self.op7(),8=>self.op8(),9=>self.op9(),98=>return,// Halt until receiving input99=>return,// End of program_=>panic!("Unrecognized opcode {}.",self.get(self.ip)),};}}/// Reads a number from STDINfnread_stdin()->isize{letmutbuffer=String::new();io::stdin().read_line(&mutbuffer).expect("STDIN read failed.");buffer.trim().parse::<isize>().unwrap()}/// Write a number to STDOUTfnwrite_stdout(number:isize){println!("{}",number);}/// Process the parameter mode and provide the value given/// as a parameterfnarg(&mutself,offset:usize)->isize{letnew_index=self.ip+offset;letmode=(self.memory[&self.ip]/10isize.pow(1+offsetasu32))%10;ifmode==2{letaddr=self.relative_base+self.memory[&new_index];letval=self.get(addrasusize);self.get(addrasusize)}elseifmode==1{self.memory[&new_index]}elseifmode==0{self.get(self.memory[&new_index]asusize)}else{panic!("Unknown parameter mode {}",mode);}}/// Returns the address to write output tofnoutput_address(&self,offset:usize)->usize{letmode=(self.memory[&self.ip]/10isize.pow(1+offsetasu32))%10;letnew_index=self.ip+offset;ifmode==0{self.memory[&new_index]asusize}elseifmode==2{(self.relative_base+self.memory[&new_index])asusize}else{panic!("Output address with weird mode");}}/// Steps the IP forward "count" steps, wrapping if neededfnstep(&mutself,count:usize){self.ip=(self.ip+count)%self.memory.len();}/// Causes the interpreter to block until receiving inputfnhalt_on_input(&mutself){// Update the last two digits from 03 to 98, but maintain// the argtype valuesself.memory.insert(self.ip,self.memory[&self.ip]+95);}/// Add [1] + [2], store in [3]fnop1(&mutself){letin1=self.arg(1);letin2=self.arg(2);letout=self.output_address(3);self.set(out,in1+in2);self.step(4);}/// Mult [1] * [2], store in [3]fnop2(&mutself){letin1=self.arg(1);letin2=self.arg(2);letout=self.output_address(3);self.set(out,in1*in2);self.step(4);}/// Read one value from STDIN and store it in [1]fnop3(&mutself){letout=self.output_address(1);letval:isize;ifself.in_buffer.is_empty(){self.halt_on_input();return;}else{val=self.in_buffer.remove(0);}self.set(out,val);self.step(2);}/// Read [1] and send it to STDOUTfnop4(&mutself){letarg=self.arg(1);self.out_buffer.push(arg);self.step(2);}/// If [1] != 0, set IP -> [2], else nothingfnop5(&mutself){ifself.arg(1)!=0{self.ip=self.arg(2)asusize;}else{self.step(3);}}/// if [1] == 0, set IP -> [2], else nothingfnop6(&mutself){ifself.arg(1)==0{self.ip=self.arg(2)asusize;}else{self.step(3);}}/// if [1] < [2], set [3] to 1, else 0fnop7(&mutself){letout=self.output_address(3);ifself.arg(1)<self.arg(2){self.set(out,1);}else{self.set(out,0);}self.step(4);}/// if [1] == [2], set [3] to 1, else 0fnop8(&mutself){letout=self.output_address(3);ifself.arg(1)==self.arg(2){self.set(out,1);}else{self.set(out,0);}self.step(4);}/// Shift relative base by [1]fnop9(&mutself){self.relative_base+=self.arg(1);self.step(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.
Had a rough time hunting down some issues that caused all of the available test cases to pass but failed my puzzle input. Turns out I should have been using "x % 10" to get the one's digit, not "x % 3" like I had.
Also, I feel like the specification for how opcode 3 (read input) works with this new relative parameter mode wasn't made super clear. But it worked out in the end. Here's my rust solution:
And my Intcode Interpreter: