From 4d197c4a89b9613009d9e01b9611d1acab6d3fbe Mon Sep 17 00:00:00 2001 From: Stefan Schwarz Date: Tue, 21 Apr 2020 23:38:00 +0200 Subject: [PATCH] day9 wip --- Cargo.toml | 6 +- src/day9/main.rs | 443 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 src/day9/main.rs diff --git a/Cargo.toml b/Cargo.toml index ad2002f..a5a2b2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,4 +28,8 @@ path = "src/day5/main.rs" [[bin]] name = "day7" -path = "src/day7/main.rs" \ No newline at end of file +path = "src/day7/main.rs" + +[[bin]] +name = "day9" +path = "src/day9/main.rs" \ No newline at end of file diff --git a/src/day9/main.rs b/src/day9/main.rs new file mode 100644 index 0000000..c24e4dd --- /dev/null +++ b/src/day9/main.rs @@ -0,0 +1,443 @@ +use std::collections::VecDeque; +use std::env; +use std::fs::File; +use std::io::{self, BufRead, BufReader}; + +#[derive(Copy, Clone)] +enum Var { + A = 1, + B, + C, +} + +// impl From for Var { +// fn from(i: usize) -> Self { +// match i { +// 0 => Var::Opcode, +// 1 => Var::A, +// 2 => Var::B, +// 3 => Var::C, +// _ => panic!("invalid variable") +// } +// } +// } +// +// impl Into for Var { +// fn into(self) -> usize { +// match self { +// Var::Opcode => 0, +// Var::A => 1, +// Var::B => 2, +// Var::C => 3, +// } +// } +// } + +#[derive(Copy, Clone, Debug)] +enum Mode { + Position, + Immediate, + Relative, +} + +impl Default for Mode { + fn default() -> Self { + Mode::Position + } +} + +impl From for Mode { + fn from(b: i64) -> Self { + match b { + 0 => Mode::Position, + 1 => Mode::Immediate, + 2 => Mode::Relative, + _ => panic!("invalid mode {}", b), + } + } +} + +#[derive(Copy, Clone, Default, Debug)] +struct Modes { + a: Mode, + b: Mode, + c: Mode, +} + +impl Modes { + fn mode_for(&self, v: &Var) -> Mode { + match v { + Var::A => self.a, + Var::B => self.b, + Var::C => self.c, + } + } +} + +impl From<(Mode, Mode, Mode)> for Modes { + fn from(modes: (Mode, Mode, Mode)) -> Self { + Modes { + a: modes.0, + b: modes.1, + c: modes.2, + } + } +} + +impl From<&ModedOpcode> for Modes { + fn from(mo: &ModedOpcode) -> Self { + mo.modes + } +} + +#[derive(Copy, Clone)] +enum Opcode { + Add, + Multiply, + Input, + Output, + JumpIfTrue, + JumpIfFalse, + LessThan, + Equals, + RelativeAdj, + Halt, +} + +impl From<&ModedOpcode> for Opcode { + fn from(mo: &ModedOpcode) -> Self { + mo.op + } +} + +impl From for Opcode { + fn from(i: i64) -> Self { + match i { + 1 => Opcode::Add, + 2 => Opcode::Multiply, + 3 => Opcode::Input, + 4 => Opcode::Output, + 5 => Opcode::JumpIfTrue, + 6 => Opcode::JumpIfFalse, + 7 => Opcode::LessThan, + 8 => Opcode::Equals, + 9 => Opcode::RelativeAdj, + 99 => Opcode::Halt, + _ => panic!("invalid opcode {}", i), + } + } +} + +struct ModedOpcode { + modes: Modes, + op: Opcode, +} + +impl From for ModedOpcode { + fn from(i: i64) -> Self { + let code = i % 100; + let modes = i / 100; + let a = (modes % 10) / 1; + let b = (modes % 100) / 10; + let c = (modes % 1000) / 100; + let modes = (Mode::from(a), Mode::from(b), Mode::from(c)); + ModedOpcode { + modes: Modes::from(modes), + op: Opcode::from(code), + } + } +} + +struct Computer { + pos: usize, + rel: i64, + program: Vec, + modes: Modes, + inputs: VecDeque, + outputs: VecDeque, + halted: bool, +} + +impl Clone for Computer { + fn clone(&self) -> Self { + Computer::from(self.program.clone()) + } +} + +impl From for Computer { + fn from(f: File) -> Self { + let f = BufReader::new(f); + let program: Vec = f + .split(b',') + .map(|o| { + let o = o.unwrap(); + let mut o = o.iter().peekable(); + let sign = if o.peek() == Some(&&b'-') { -1 } else { 1 }; + o.filter(|i| **i >= b'0' && **i <= b'9') + .fold(0, |s, i| ((i - b'0') as i64 + 10 * s)) + * sign + }) + .collect(); + Computer::from(program) + } +} + +impl From> for Computer { + fn from(program: Vec) -> Self { + Computer { + pos: 0, + rel: 0, + program: program, + modes: Default::default(), + inputs: VecDeque::new(), + outputs: VecDeque::new(), + halted: false, + } + } +} + +impl Computer { + fn clone_with_modified_program(&self, u: Vec<(usize, i64)>) -> Computer { + let mut computer = self.clone(); + for (pos, val) in u { + computer.program[pos] = val; + } + computer + } + + fn clone_with_input(&self, input: Vec) -> Computer { + let mut computer = self.clone(); + computer.inputs = VecDeque::from(input); + computer + } + + fn run(&mut self) { + while !self.halted { + self.step(); + } + } + + fn run_until_output(&mut self) -> Option { + loop { + self.step(); + if self.outputs.len() > 0 { + return self.outputs.pop_front(); + } + if self.halted { + return None; + } + } + } + + fn run_must_output(&mut self) -> i64 { + self.run_until_output() + .expect("computer halted without output") + } + + fn run_io(&mut self, input: Vec) -> Option { + input.iter().for_each(|i| self.inputs.push_back(*i)); + self.run_until_output() + } + + fn step(&mut self) { + let instruction = self.program[self.pos]; + let instruction = ModedOpcode::from(instruction); + self.modes = Modes::from(&instruction); + let advance = match Opcode::from(&instruction) { + Opcode::Add => self.add(), + Opcode::Multiply => self.multiply(), + Opcode::Input => self.input(), + Opcode::Output => self.output(), + Opcode::JumpIfTrue => self.jump_if_true(), + Opcode::JumpIfFalse => self.jump_if_false(), + Opcode::LessThan => self.less_than(), + Opcode::Equals => self.equals(), + Opcode::RelativeAdj => self.relative_adj(), + Opcode::Halt => self.halt(), + }; + self.pos += advance; + } + + fn get_pos(&self, pos: usize) -> i64 { + *self.program.get(pos).unwrap_or(&0) + } + + fn get(&self, v: &Var) -> i64 { + let x = *self.program.get(self.pos + *v as usize).unwrap_or(&0); + match self.modes.mode_for(v) { + Mode::Position => self.get_pos(x as usize), + Mode::Immediate => x, + Mode::Relative => self.get_pos((self.rel + x) as usize), + } + } + + fn get_a(&self) -> i64 { + self.get(&Var::A) + } + + fn get_b(&self) -> i64 { + self.get(&Var::B) + } + + fn set(&mut self, v: &Var, value: i64) { + let length = self.program.len(); + let want = self.pos + *v as usize; + let want = match self.modes.mode_for(v) { + Mode::Position => self.get_pos(want), + Mode::Immediate => want as i64, + Mode::Relative => self.get_pos((self.rel + want as i64) as usize), + } as usize; + if length < want { + let missing = (want - length) + 2; + self.program.extend_from_slice(&vec![0; missing]) + } + self.program[want] = value; + } + + fn set_a(&mut self, value: i64) { + self.set(&Var::A, value) + } + + fn set_c(&mut self, value: i64) { + self.set(&Var::C, value) + } + + fn add(&mut self) -> usize { + self.set_c(self.get_a() + self.get_b()); + 4 + } + + fn multiply(&mut self) -> usize { + self.set_c(self.get_a() * self.get_b()); + 4 + } + + fn input(&mut self) -> usize { + let value = self.inputs.pop_front().expect("no input provided"); + self.set_a(value); + 2 + } + + fn output(&mut self) -> usize { + self.outputs.push_back(self.get_a()); + 2 + } + + fn jump_if_true(&mut self) -> usize { + if self.get_a() > 0 { + self.pos = self.get_b() as usize; + return 0; + } + 3 + } + + fn jump_if_false(&mut self) -> usize { + if self.get_a() == 0 { + self.pos = self.get_b() as usize; + return 0; + } + 3 + } + + fn less_than(&mut self) -> usize { + if self.get_a() < self.get_b() { + self.set_c(1) + } else { + self.set_c(0) + } + 4 + } + + fn equals(&mut self) -> usize { + if self.get_a() == self.get_b() { + self.set_c(1) + } else { + self.set_c(0) + } + 4 + } + + fn relative_adj(&mut self) -> usize { + self.rel = self.rel + self.get_a(); + 2 + } + + fn halt(&mut self) -> usize { + self.halted = true; + 0 + } +} + +fn main() -> io::Result<()> { + let filename = env::args().nth(1).expect("provide file as first param"); + let computer = Computer::from(File::open(filename)?); + let result = computer.clone_with_input(vec![1]).run_must_output(); + println!("{:?}", result); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn example1() { + let program = vec![ + 109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99, + ]; + let mut computer = Computer::from(program.clone()); + computer.run(); + assert_eq!(Vec::from(computer.outputs), program) + } + + #[test] + fn example2() { + assert_eq!( + Computer::from(vec![1102, 34915192, 34915192, 7, 4, 7, 99, 0]).run_must_output(), + 1219070632396864 + ) + } + + #[test] + fn example3() { + assert_eq!( + Computer::from(vec![104,1125899906842624,99]).run_must_output(), + 1125899906842624 + ) + } + + #[test] + fn day5exampe1() { + let computer = Computer::from(vec![3,9,8,9,10,9,4,9,99,-1,8]); + assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0); + assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1); + } + + #[test] + fn day5exampe2() { + let computer = Computer::from(vec![3,3,1108,-1,8,3,4,3,99]); + assert_eq!(computer.clone_with_input(vec![1]).run_must_output(), 0); + assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1); + } + + #[test] + fn day5exampe3() { + let computer = Computer::from(vec![3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9]); + assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0); + assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1); + let computer = Computer::from(vec![3,3,1105,-1,9,1101,0,0,12,4,12,99,1]); + assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 0); + assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1); + } + + #[test] + fn day5exampe4() { + let computer = Computer::from(vec![3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31, +1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104, +999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99]); + assert_eq!(computer.clone_with_input(vec![0]).run_must_output(), 999); + assert_eq!(computer.clone_with_input(vec![8]).run_must_output(), 1000); + assert_eq!(computer.clone_with_input(vec![9]).run_must_output(), 1001); + } +}