diff --git a/src/main.rs b/src/main.rs index 2bad024..33ea898 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ mod tasks; fn main() { - tasks::day05::run(); + tasks::day09::run(); } diff --git a/src/tasks/day05.rs b/src/tasks/day05.rs index 562e2ac..554372c 100644 --- a/src/tasks/day05.rs +++ b/src/tasks/day05.rs @@ -1,19 +1,25 @@ +use std::collections::HashMap; + +pub type RAM = HashMap; + #[allow(dead_code)] pub fn run() { let input = std::fs::read_to_string("input/day05.txt").unwrap(); - let ram: Vec = input + let ram: RAM = input .split(",") - .map(|s| s.parse::().unwrap()) + .enumerate() + .map(|(i, s)| (i, s.parse::().unwrap())) .collect(); task1(ram.clone()); task2(ram.clone()); } pub struct IntCodeComputer { - input_storage: Vec, - output_storage: Vec, + input_storage: Vec, + output_storage: Vec, pc: usize, - ram: Vec, + ram: RAM, + relative_base_offset: i128, } #[derive(PartialEq, Debug)] @@ -26,35 +32,44 @@ enum OpCode { JumpIfFalse, LessThan, Equals, + AdjustRelBase, Terminate, } #[derive(Debug)] enum OpParam { - Immediate(i32), + Immediate(i128), Memory(usize), + Relative(i128), } impl OpParam { - fn from(val: i32, type_number: i32) -> Self { + fn from(val: i128, type_number: i128) -> Self { match type_number { 0 => OpParam::Memory(val as usize), 1 => OpParam::Immediate(val), + 2 => OpParam::Relative(val), _ => unreachable!("unexpected parameter"), } } - fn retrieve(&self, memory: &Vec) -> i32 { + fn retrieve(&self, memory: &RAM, relative_base_offset: i128) -> i128 { match self { OpParam::Immediate(v) => *v, - OpParam::Memory(i) => memory[*i], + OpParam::Memory(i) => memory.get_default(*i), + OpParam::Relative(i) => memory.get_default((relative_base_offset + *i) as usize), } } - fn store(&self, memory: &mut Vec, value: i32) { + fn store(&self, memory: &mut RAM, value: i128, relative_base_offset: i128) { match self { OpParam::Immediate(_) => panic!("cannot save to immediate position"), - OpParam::Memory(i) => memory[*i] = value, + OpParam::Memory(i) => { + memory.insert(*i, value); + } + OpParam::Relative(i) => { + memory.insert((relative_base_offset + *i) as usize, value); + } } } } @@ -66,9 +81,9 @@ struct Op { } impl Op { - fn from(pc: usize, memory: &Vec) -> Self { + fn from(pc: usize, memory: &RAM) -> Self { //opcode: 123xx -> 1, 2, 3: parameter type for parameters 1-3, xx = actual op code - let mut opcode = memory[pc]; + let mut opcode = memory.get_default(pc); let p_type1 = opcode / 10_000; opcode %= 10_000; let p_type2 = opcode / 1000; @@ -79,57 +94,61 @@ impl Op { 1 => Op { opcode: OpCode::Add, params: vec![ - OpParam::from(memory[pc + 1], p_type3), - OpParam::from(memory[pc + 2], p_type2), - OpParam::from(memory[pc + 3], p_type1), + OpParam::from(memory.get_default(pc + 1), p_type3), + OpParam::from(memory.get_default(pc + 2), p_type2), + OpParam::from(memory.get_default(pc + 3), p_type1), ], }, 2 => Op { opcode: OpCode::Multiply, params: vec![ - OpParam::from(memory[pc + 1], p_type3), - OpParam::from(memory[pc + 2], p_type2), - OpParam::from(memory[pc + 3], p_type1), + OpParam::from(memory.get_default(pc + 1), p_type3), + OpParam::from(memory.get_default(pc + 2), p_type2), + OpParam::from(memory.get_default(pc + 3), p_type1), ], }, 3 => Op { opcode: OpCode::Input, - params: vec![OpParam::from(memory[pc + 1], p_type3)], + params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)], }, 4 => Op { opcode: OpCode::Output, - params: vec![OpParam::from(memory[pc + 1], p_type3)], + params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)], }, 5 => Op { opcode: OpCode::JumpIfTrue, params: vec![ - OpParam::from(memory[pc + 1], p_type3), - OpParam::from(memory[pc + 2], p_type2), + OpParam::from(memory.get_default(pc + 1), p_type3), + OpParam::from(memory.get_default(pc + 2), p_type2), ], }, 6 => Op { opcode: OpCode::JumpIfFalse, params: vec![ - OpParam::from(memory[pc + 1], p_type3), - OpParam::from(memory[pc + 2], p_type2), + OpParam::from(memory.get_default(pc + 1), p_type3), + OpParam::from(memory.get_default(pc + 2), p_type2), ], }, 7 => Op { opcode: OpCode::LessThan, params: vec![ - OpParam::from(memory[pc + 1], p_type3), - OpParam::from(memory[pc + 2], p_type2), - OpParam::from(memory[pc + 3], p_type1), + OpParam::from(memory.get_default(pc + 1), p_type3), + OpParam::from(memory.get_default(pc + 2), p_type2), + OpParam::from(memory.get_default(pc + 3), p_type1), ], }, 8 => Op { opcode: OpCode::Equals, params: vec![ - OpParam::from(memory[pc + 1], p_type3), - OpParam::from(memory[pc + 2], p_type2), - OpParam::from(memory[pc + 3], p_type1), + OpParam::from(memory.get_default(pc + 1), p_type3), + OpParam::from(memory.get_default(pc + 2), p_type2), + OpParam::from(memory.get_default(pc + 3), p_type1), ], }, + 9 => Op { + opcode: OpCode::AdjustRelBase, + params: vec![OpParam::from(memory.get_default(pc + 1), p_type3)], + }, 99 => Op { opcode: OpCode::Terminate, params: vec![], @@ -140,12 +159,13 @@ impl Op { } impl IntCodeComputer { - pub fn new(input: Vec, memory: Vec) -> Self { + pub fn new(input: Vec, memory: RAM) -> Self { IntCodeComputer { input_storage: input, output_storage: Vec::new(), pc: 0, ram: memory, + relative_base_offset: 0, } } @@ -164,60 +184,73 @@ impl IntCodeComputer { while op.opcode != OpCode::Terminate { match op.opcode { OpCode::Add => { - let r = op.params[0].retrieve(&self.ram) + op.params[1].retrieve(&self.ram); - op.params[2].store(&mut self.ram, r); + let r = op.params[0].retrieve(&self.ram, self.relative_base_offset) + + op.params[1].retrieve(&self.ram, self.relative_base_offset); + op.params[2].store(&mut self.ram, r, self.relative_base_offset); self.pc += 4; } OpCode::Multiply => { - let r = op.params[0].retrieve(&self.ram) * op.params[1].retrieve(&self.ram); - op.params[2].store(&mut self.ram, r); + let r = op.params[0].retrieve(&self.ram, self.relative_base_offset) + * op.params[1].retrieve(&self.ram, self.relative_base_offset); + op.params[2].store(&mut self.ram, r, self.relative_base_offset); self.pc += 4; } OpCode::Input => { if let Some(v) = inputs.next() { - op.params[0].store(&mut self.ram, *v); + op.params[0].store(&mut self.ram, *v, self.relative_base_offset); self.pc += 2; } else { return false; } } OpCode::Output => { - self.output_storage.push(op.params[0].retrieve(&self.ram)); + self.output_storage + .push(op.params[0].retrieve(&self.ram, self.relative_base_offset)); self.pc += 2; } OpCode::JumpIfTrue => { - if op.params[0].retrieve(&self.ram) > 0 { - self.pc = op.params[1].retrieve(&self.ram) as usize; + if op.params[0].retrieve(&self.ram, self.relative_base_offset) > 0 { + self.pc = + op.params[1].retrieve(&self.ram, self.relative_base_offset) as usize; } else { self.pc += 3; } } OpCode::JumpIfFalse => { - if op.params[0].retrieve(&self.ram) == 0 { - self.pc = op.params[1].retrieve(&self.ram) as usize; + if op.params[0].retrieve(&self.ram, self.relative_base_offset) == 0 { + self.pc = + op.params[1].retrieve(&self.ram, self.relative_base_offset) as usize; } else { self.pc += 3; } } OpCode::LessThan => { - let r = if op.params[0].retrieve(&self.ram) < op.params[1].retrieve(&self.ram) { - 1 - } else { - 0 - }; - op.params[2].store(&mut self.ram, r); - self.pc += 4; - } - OpCode::Equals => { - let r = if op.params[0].retrieve(&self.ram) == op.params[1].retrieve(&self.ram) + let r = if op.params[0].retrieve(&self.ram, self.relative_base_offset) + < op.params[1].retrieve(&self.ram, self.relative_base_offset) { 1 } else { 0 }; - op.params[2].store(&mut self.ram, r); + op.params[2].store(&mut self.ram, r, self.relative_base_offset); self.pc += 4; } + OpCode::Equals => { + let r = if op.params[0].retrieve(&self.ram, self.relative_base_offset) + == op.params[1].retrieve(&self.ram, self.relative_base_offset) + { + 1 + } else { + 0 + }; + op.params[2].store(&mut self.ram, r, self.relative_base_offset); + self.pc += 4; + } + OpCode::AdjustRelBase => { + self.relative_base_offset += + op.params[0].retrieve(&self.ram, self.relative_base_offset); + self.pc += 2; + } OpCode::Terminate => {} } op = Op::from(self.pc, &self.ram); @@ -225,7 +258,7 @@ impl IntCodeComputer { return true; } - pub fn set_input(&mut self, input: &[i32]) { + pub fn set_input(&mut self, input: &[i128]) { self.input_storage.clear(); for x in input { self.input_storage.push(*x); @@ -236,21 +269,31 @@ impl IntCodeComputer { self.output_storage.clear(); } - pub fn get_output(&self) -> &[i32] { + pub fn get_output(&self) -> &[i128] { self.output_storage.as_slice() } } -fn task1(ram: Vec) { +fn task1(ram: RAM) { let mut computer = IntCodeComputer::new(vec![1], ram); computer.run_until_end(); println!("{:?}", computer.get_output()); println!("Task 1: {}", computer.get_output().last().unwrap()); } -fn task2(ram: Vec) { +fn task2(ram: RAM) { let mut computer = IntCodeComputer::new(vec![5], ram); computer.run_until_end(); println!("{:?}", computer.get_output()); println!("Task 2: {}", computer.get_output().last().unwrap()); } + +trait Easy { + fn get_default(&self, index: usize) -> i128; +} + +impl Easy for RAM { + fn get_default(&self, index: usize) -> i128 { + **self.get(&index).get_or_insert(&0) + } +} diff --git a/src/tasks/day07.rs b/src/tasks/day07.rs index 4a31e32..e5e0726 100644 --- a/src/tasks/day07.rs +++ b/src/tasks/day07.rs @@ -6,20 +6,23 @@ pub fn run() { let prog_code: Vec<_> = std::fs::read_to_string("input/day07.txt") .unwrap() .split(",") - .map(|s| s.parse::().unwrap()) + .map(|s| s.parse::().unwrap()) .collect(); task1(prog_code.clone()); task2(prog_code.clone()); } -fn task1(input: Vec) { +fn task1(input: Vec) { let phases = vec![0, 1, 2, 3, 4]; let result = phases .iter() .permutations(phases.len()) .map(|perm| { perm.iter().fold(0, |signal, phase| { - let mut computer = IntCodeComputer::new(vec![**phase, signal], input.clone()); + let mut computer = IntCodeComputer::new( + vec![**phase, signal], + input.clone().into_iter().enumerate().collect(), + ); computer.run_until_end(); *computer.get_output().last().unwrap() }) @@ -28,7 +31,7 @@ fn task1(input: Vec) { println!("Task 1: best signal is {}", result.unwrap()); } -fn task2(input: Vec) { +fn task2(input: Vec) { let phases = vec![5, 6, 7, 8, 9]; let result = phases .iter() @@ -37,7 +40,10 @@ fn task2(input: Vec) { let mut machines: Vec = perm .iter() .map(|phase| { - let mut comp = IntCodeComputer::new(vec![**phase], input.clone()); + let mut comp = IntCodeComputer::new( + vec![**phase], + input.clone().into_iter().enumerate().collect(), + ); comp.run_until_input_empty(); comp }) diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index c474e40..30a8d06 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -5,3 +5,4 @@ pub mod day05; pub mod day06; pub mod day07; pub mod day08; +pub mod day09;