diff --git a/2019/input/day5.txt b/2019/input/day5.txt new file mode 100644 index 0000000..e659ce6 --- /dev/null +++ b/2019/input/day5.txt @@ -0,0 +1 @@ +3,225,1,225,6,6,1100,1,238,225,104,0,1101,61,45,225,102,94,66,224,101,-3854,224,224,4,224,102,8,223,223,1001,224,7,224,1,223,224,223,1101,31,30,225,1102,39,44,224,1001,224,-1716,224,4,224,102,8,223,223,1001,224,7,224,1,224,223,223,1101,92,41,225,101,90,40,224,1001,224,-120,224,4,224,102,8,223,223,1001,224,1,224,1,223,224,223,1101,51,78,224,101,-129,224,224,4,224,1002,223,8,223,1001,224,6,224,1,224,223,223,1,170,13,224,101,-140,224,224,4,224,102,8,223,223,1001,224,4,224,1,223,224,223,1101,14,58,225,1102,58,29,225,1102,68,70,225,1002,217,87,224,101,-783,224,224,4,224,102,8,223,223,101,2,224,224,1,224,223,223,1101,19,79,225,1001,135,42,224,1001,224,-56,224,4,224,102,8,223,223,1001,224,6,224,1,224,223,223,2,139,144,224,1001,224,-4060,224,4,224,102,8,223,223,101,1,224,224,1,223,224,223,1102,9,51,225,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1008,677,226,224,102,2,223,223,1006,224,329,101,1,223,223,108,677,677,224,102,2,223,223,1005,224,344,101,1,223,223,107,677,677,224,1002,223,2,223,1005,224,359,101,1,223,223,1107,226,677,224,1002,223,2,223,1005,224,374,1001,223,1,223,1008,677,677,224,102,2,223,223,1006,224,389,1001,223,1,223,1007,677,677,224,1002,223,2,223,1006,224,404,1001,223,1,223,8,677,226,224,102,2,223,223,1005,224,419,1001,223,1,223,8,226,226,224,102,2,223,223,1006,224,434,101,1,223,223,1107,226,226,224,1002,223,2,223,1006,224,449,101,1,223,223,1107,677,226,224,102,2,223,223,1005,224,464,101,1,223,223,1108,226,226,224,102,2,223,223,1006,224,479,1001,223,1,223,7,677,677,224,1002,223,2,223,1006,224,494,101,1,223,223,7,677,226,224,102,2,223,223,1005,224,509,101,1,223,223,1108,226,677,224,1002,223,2,223,1006,224,524,101,1,223,223,8,226,677,224,1002,223,2,223,1005,224,539,101,1,223,223,1007,226,226,224,102,2,223,223,1006,224,554,1001,223,1,223,108,226,226,224,1002,223,2,223,1006,224,569,1001,223,1,223,1108,677,226,224,102,2,223,223,1005,224,584,101,1,223,223,108,226,677,224,102,2,223,223,1005,224,599,101,1,223,223,1007,226,677,224,102,2,223,223,1006,224,614,1001,223,1,223,1008,226,226,224,1002,223,2,223,1006,224,629,1001,223,1,223,107,226,226,224,1002,223,2,223,1006,224,644,101,1,223,223,7,226,677,224,102,2,223,223,1005,224,659,1001,223,1,223,107,677,226,224,102,2,223,223,1005,224,674,1001,223,1,223,4,223,99,226 diff --git a/2019/src/computer.rs b/2019/src/computer.rs new file mode 100644 index 0000000..10a6150 --- /dev/null +++ b/2019/src/computer.rs @@ -0,0 +1,129 @@ +type Address = i32; + +#[derive(Debug, Eq, PartialEq)] +enum Instruction { + Add(Mode, Mode), + Multiply(Mode, Mode), + Input(Mode), + Output(Mode), + Halt, +} + +#[derive(Debug, Eq, PartialEq)] +enum Mode { + Immediate, + Address, +} + +struct Memory<'a> { + mem: &'a mut [i32], +} + +fn decode(mut instruction: i32) -> Instruction { + let opcode = divmod(&mut instruction, 100); + + match opcode { + 1 => { + // let mode3 = divmod(&mut instruction, 10); + // Parameters that an instruction writes to will never be in immediate mode. + Instruction::Add( + Mode::from(divmod(&mut instruction, 10)), + Mode::from(divmod(&mut instruction, 10)), + ) + } + 2 => Instruction::Multiply( + Mode::from(divmod(&mut instruction, 10)), + Mode::from(divmod(&mut instruction, 10)), + ), + 3 => Instruction::Input(Mode::from(divmod(&mut instruction, 10))), + 4 => Instruction::Output(Mode::from(divmod(&mut instruction, 10))), + 99 => Instruction::Halt, + _ => panic!("Invalid opcode: {}", opcode), + } +} + +impl<'a> Memory<'a> { + pub fn new(mem: &'a mut [i32]) -> Self { + Memory { mem } + } + + pub fn read(&self, value: i32, mode: Mode) -> i32 { + match mode { + Mode::Immediate => value, + Mode::Address => self.mem[value as usize], + } + } + + fn write(&mut self, address: Address, value: i32) { + self.mem[address as usize] = value; + } + + fn run(&mut self, noun: i32, verb: i32) { + self.write(1, noun); + self.write(2, verb); + let mut ip = 0; // instruction pointer + + loop { + match decode(self.read(ip, Mode::Address)) { + Instruction::Add(mode1, mode2) => { + let result = self.read(ip + 1, mode1) + self.read(ip + 1, mode2); + self.write(ip + 3, result); + ip += 4; + } + Instruction::Multiply(mode1, mode2) => { + let result = self.read(ip + 1, mode1) * self.read(ip + 1, mode2); + self.write(ip + 3, result); + ip += 4; + } + Instruction::Input(mode) => { + ip += 2; + } + Instruction::Output(mode) => { + ip += 2; + } + Instruction::Halt => break, + } + } + } +} + +fn divmod(value: &mut i32, divisor: i32) -> i32 { + let res = *value % divisor; + *value /= divisor; + res +} + +impl From for Mode { + fn from(mode: i32) -> Self { + match mode { + 0 => Mode::Address, + 1 => Mode::Immediate, + _ => unreachable!(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::input; + use std::fs; + + #[test] + fn test_decode() { + assert_eq!( + decode(1002), + Instruction::Multiply(Mode::Address, Mode::Immediate) + ) + } + + fn test_day2() { + let input = fs::read_to_string("input/day2.txt").unwrap(); + let mut data = input::read_separated_line(',', &input).unwrap(); + let mut program = Memory::new(&mut data); + + // Check that day2 still works wirh run through this implementation + program.run(12, 2); + assert_eq!(program.read(0, Mode::Address), 4138658); + } +} diff --git a/2019/src/lib.rs b/2019/src/lib.rs index 3a6660f..2e7a87e 100644 --- a/2019/src/lib.rs +++ b/2019/src/lib.rs @@ -1,2 +1,3 @@ +pub mod computer; pub mod input; pub mod point;