From e361844dd9a27d4426520fb6f0348c8a539535d5 Mon Sep 17 00:00:00 2001 From: Armin Friedl Date: Sat, 7 Dec 2019 18:57:42 +0100 Subject: [PATCH] Day 5 --- day5/2/Cargo.toml | 11 + day5/2/input | 678 +++++++++++++++++++++++++++++++++++++++++++++ day5/2/src/main.rs | 330 ++++++++++++++++++++++ 3 files changed, 1019 insertions(+) create mode 100644 day5/2/Cargo.toml create mode 100644 day5/2/input create mode 100644 day5/2/src/main.rs diff --git a/day5/2/Cargo.toml b/day5/2/Cargo.toml new file mode 100644 index 0000000..07cb7e5 --- /dev/null +++ b/day5/2/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "intcode" +version = "0.1.0" +authors = ["Armin Friedl "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +env_logger="0.7" \ No newline at end of file diff --git a/day5/2/input b/day5/2/input new file mode 100644 index 0000000..d4854c2 --- /dev/null +++ b/day5/2/input @@ -0,0 +1,678 @@ +3 +225 +1 +225 +6 +6 +1100 +1 +238 +225 +104 +0 +1101 +90 +60 +224 +1001 +224 +-150 +224 +4 +224 +1002 +223 +8 +223 +1001 +224 +7 +224 +1 +224 +223 +223 +1 +57 +83 +224 +1001 +224 +-99 +224 +4 +224 +1002 +223 +8 +223 +1001 +224 +5 +224 +1 +223 +224 +223 +1102 +92 +88 +225 +101 +41 +187 +224 +1001 +224 +-82 +224 +4 +224 +1002 +223 +8 +223 +101 +7 +224 +224 +1 +224 +223 +223 +1101 +7 +20 +225 +1101 +82 +64 +225 +1002 +183 +42 +224 +101 +-1554 +224 +224 +4 +224 +102 +8 +223 +223 +1001 +224 +1 +224 +1 +224 +223 +223 +1102 +70 +30 +224 +101 +-2100 +224 +224 +4 +224 +102 +8 +223 +223 +101 +1 +224 +224 +1 +224 +223 +223 +2 +87 +214 +224 +1001 +224 +-2460 +224 +4 +224 +1002 +223 +8 +223 +101 +7 +224 +224 +1 +223 +224 +223 +102 +36 +180 +224 +1001 +224 +-1368 +224 +4 +224 +1002 +223 +8 +223 +1001 +224 +5 +224 +1 +223 +224 +223 +1102 +50 +38 +225 +1102 +37 +14 +225 +1101 +41 +20 +225 +1001 +217 +7 +224 +101 +-25 +224 +224 +4 +224 +1002 +223 +8 +223 +101 +2 +224 +224 +1 +224 +223 +223 +1101 +7 +30 +225 +1102 +18 +16 +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 +7 +226 +226 +224 +102 +2 +223 +223 +1006 +224 +329 +101 +1 +223 +223 +1107 +677 +226 +224 +102 +2 +223 +223 +1006 +224 +344 +1001 +223 +1 +223 +8 +677 +226 +224 +1002 +223 +2 +223 +1005 +224 +359 +101 +1 +223 +223 +107 +677 +677 +224 +1002 +223 +2 +223 +1006 +224 +374 +101 +1 +223 +223 +7 +677 +226 +224 +1002 +223 +2 +223 +1006 +224 +389 +101 +1 +223 +223 +108 +677 +226 +224 +1002 +223 +2 +223 +1005 +224 +404 +101 +1 +223 +223 +1108 +677 +226 +224 +102 +2 +223 +223 +1005 +224 +419 +101 +1 +223 +223 +8 +226 +677 +224 +102 +2 +223 +223 +1006 +224 +434 +1001 +223 +1 +223 +1008 +677 +677 +224 +1002 +223 +2 +223 +1005 +224 +449 +1001 +223 +1 +223 +1107 +226 +677 +224 +102 +2 +223 +223 +1006 +224 +464 +101 +1 +223 +223 +107 +226 +677 +224 +1002 +223 +2 +223 +1006 +224 +479 +1001 +223 +1 +223 +7 +226 +677 +224 +102 +2 +223 +223 +1005 +224 +494 +1001 +223 +1 +223 +8 +677 +677 +224 +102 +2 +223 +223 +1006 +224 +509 +1001 +223 +1 +223 +1108 +677 +677 +224 +102 +2 +223 +223 +1005 +224 +524 +1001 +223 +1 +223 +1108 +226 +677 +224 +1002 +223 +2 +223 +1005 +224 +539 +101 +1 +223 +223 +107 +226 +226 +224 +102 +2 +223 +223 +1006 +224 +554 +1001 +223 +1 +223 +1007 +226 +226 +224 +102 +2 +223 +223 +1005 +224 +569 +1001 +223 +1 +223 +1008 +226 +226 +224 +102 +2 +223 +223 +1005 +224 +584 +101 +1 +223 +223 +1007 +677 +677 +224 +1002 +223 +2 +223 +1005 +224 +599 +1001 +223 +1 +223 +108 +677 +677 +224 +1002 +223 +2 +223 +1006 +224 +614 +1001 +223 +1 +223 +1007 +226 +677 +224 +1002 +223 +2 +223 +1006 +224 +629 +101 +1 +223 +223 +1008 +677 +226 +224 +102 +2 +223 +223 +1005 +224 +644 +101 +1 +223 +223 +1107 +226 +226 +224 +1002 +223 +2 +223 +1005 +224 +659 +1001 +223 +1 +223 +108 +226 +226 +224 +1002 +223 +2 +223 +1005 +224 +674 +101 +1 +223 +223 +4 +223 +99 +226 \ No newline at end of file diff --git a/day5/2/src/main.rs b/day5/2/src/main.rs new file mode 100644 index 0000000..de38572 --- /dev/null +++ b/day5/2/src/main.rs @@ -0,0 +1,330 @@ +#[allow(unused_imports)] +use log::{debug, error, info, trace, warn}; + +use env_logger; + +use std::fs::File; +use std::io::{BufReader, BufRead, stdin, stdout, Write}; +use std::error::Error; +use std::result::Result; + +#[derive(Debug)] +struct Computer { + mem: Vec, + intp: *mut i32, // here will be dragons +} + +#[derive(Debug)] +struct Opcode { + inst: u8, + mode: Vec, +} + +#[derive(Debug)] +enum Opmode { + Position, + Immediate +} + +impl From for Opcode { + fn from(num: i32) -> Self { + let mut x = num; + let mut opcode = Opcode { + inst: (num%100) as u8, + mode: Vec::new() + }; + + x /= 100; // strip 2 least significant digits + + loop { + match x%10 { + 0 => opcode.mode.push(Opmode::Position), + 1 => opcode.mode.push(Opmode::Immediate), + _ => panic!{"Invalid opmode: {}", x%10} + } + + x /= 10; + if x == 0 {break} + } + + opcode + } +} + +#[allow(dead_code)] +impl Computer { + fn new() -> Self { + let mut mem = vec![0]; + let intp = &mut mem[0] as *mut i32; + + Computer {mem, intp} + } + + fn push(&mut self, val: i32) { + if self.mem[0] == 0 { // we are in init state + self.mem[0] = val + } else { + self.mem.push(val); + } + } + + fn set(&mut self, pos: usize, val: i32) { + self.mem[pos] = val; + } + + fn compute(&mut self) -> i32 { + // first reset the pointer just to be sure + self.intp = &mut self.mem[0] as *mut i32; + + loop { + let opcode: Opcode = self._expect_next(&Opmode::Immediate).into(); + trace!{"{:?}", opcode} + + match opcode.inst { + 1 => self._add(&opcode.mode), + 2 => self._mul(&opcode.mode), + 3 => self._input(), + 4 => self._output(&opcode.mode), + 5 => self._jump_true(&opcode.mode), + 6 => self._jump_false(&opcode.mode), + 7 => self._less_than(&opcode.mode), + 8 => self._equals(&opcode.mode), + 99 => break, + _ => panic!{"Invalid opcode {}", opcode.inst}, + } + } + + self.mem[0] + } + + fn _add(&mut self, modes: &[Opmode]) { + let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position)); + let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position)); + let pos = self._expect_next(&Opmode::Immediate) as usize; + debug!{"Adding {} and {} to position {}", op1, op2, pos} + + self.mem[pos] = op1 + op2; + trace!{"{:?}", self} + } + + fn _mul(&mut self, modes: &[Opmode]) { + let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position)); + let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position)); + let pos = self._expect_next(&Opmode::Immediate) as usize; + debug!{"Multiplying {} and {} to position {}", op1, op2, pos} + + self.mem[pos] = op1*op2; + trace!{"{:?}", self} + } + + fn _input(&mut self) { + let pos = self._expect_next(&Opmode::Immediate) as usize; + debug!{"Reading input to position {}", pos} + + let mut input = String::new(); + print!{"Input: "}; + stdout().flush().unwrap(); + + stdin().read_line(&mut input).unwrap(); + + self.mem[pos] = input.trim().parse().expect("Invalid input"); + trace!{"{:?}", self} + } + + fn _output(&mut self, modes: &[Opmode]) { + let op = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position)); + debug!{"Writing output {}", op} + + println!("Output: {}", op); + trace!{"{:?}", self} + } + + fn _jump_true(&mut self, modes: &[Opmode]) { + let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position)); + let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position)); + debug!{"Jump true for op {} to position {}", op1, op2} + + if op1 == 0 {return;} + + + debug!{"Jumping to {}", op2} + self.intp = &mut self.mem[0] as *mut i32; // reset pointer + unsafe { + self.intp = self.intp.offset(op2 as isize); + } + trace!{"{:?}", self} + } + + fn _jump_false(&mut self, modes: &[Opmode]) { + let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position)); + let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position)); + debug!{"Jump false for op {} to position {}", op1, op2} + + if op1 != 0 {return;} + + self.intp = &mut self.mem[0] as *mut i32; // reset pointer + unsafe { + self.intp = self.intp.offset(op2 as isize); + } + trace!{"{:?}", self} + } + + fn _less_than(&mut self, modes: &[Opmode]) { + let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position)); + let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position)); + let position = self._expect_next(&Opmode::Immediate) as usize; + + debug!{"Less than {} < {} writing to position {}", op1, op2, position} + + if op1 < op2 { + self.mem[position] = 1; + } else { + self.mem[position] = 0; + } + + trace!{"{:?}", self} + } + + fn _equals(&mut self, modes: &[Opmode]) { + let op1 = self._expect_next(&modes.get(0).unwrap_or(&Opmode::Position)); + let op2 = self._expect_next(&modes.get(1).unwrap_or(&Opmode::Position)); + let position = self._expect_next(&Opmode::Immediate) as usize; + + debug!{"Equals {} == {} writing to position {}", op1, op2, position} + + if op1 == op2 { + self.mem[position] = 1; + } else { + self.mem[position] = 0; + } + + trace!{"{:?}", self} + } + + fn _next(&mut self) -> Option { + unsafe{ // Dragons + + // overflow check, smart cpu + let lstp = self.mem.last_mut().unwrap() as *mut i32; + if self.intp == lstp.offset(1) { + return None; + } + + let op = *self.intp; + self.intp = self.intp.offset(1); + + Some(op) + } + } + + fn _expect_next(&mut self, mode: &Opmode) -> i32 { + let next = self._next().expect("Exhausted"); + + match mode { + Opmode::Position => { + trace!{"Next in position {} = {}", next, self.mem[next as usize]} + self.mem[next as usize] + }, + Opmode::Immediate => { + trace!{"Next in immediate = {}", next} + next + } + } + } +} + +impl Clone for Computer { + fn clone(&self) -> Self { + let mut mem = self.mem.clone(); + let intp = &mut mem[0] as *mut i32; + + Computer { mem, intp } + } +} + +fn main() -> Result<(), Box>{ + env_logger::init(); + + let input = File::open("input")?; + let reader = BufReader::new(input); + + let mut computer = Computer::new(); + + reader.lines() + .filter_map(Result::ok) // transform into Option and filter + .filter_map(|l| l.parse().ok()) // parse String to i32 transform to Option and filter + .for_each(|i| computer.push(i)); // push instruction to computer + + computer.compute(); + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn tc1() { + env_logger::init(); + let mut computer = Computer::new(); + let mem = vec![3,9,8,9,10,9,4,9,99,-1,8]; + mem.iter().for_each(|&n| computer.push(n)); + println!{"{:?}", computer} + computer.compute(); + println!{"{:?}", computer} + } + + #[test] + fn tc2() { + env_logger::init(); + let mut computer = Computer::new(); + let mem = vec![3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9]; + mem.iter().for_each(|&n| computer.push(n)); + println!{"{:?}", computer} + computer.compute(); + println!{"{:?}", computer} + } + + #[test] + fn tc3() { + env_logger::init(); + let mut computer = Computer::new(); + let mem = 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]; + mem.iter().for_each(|&n| computer.push(n)); + debug!{"{:?}", computer} + computer.compute(); + debug!{"{:?}", computer} + } +} + +#[cfg(test)] +mod regression { + use super::*; + + #[test] + fn tc1() { + let mut computer = Computer::new(); + let mem = vec![1002,4,3,4,33]; + mem.iter().for_each(|&n| computer.push(n)); + println!{"{:?}", computer} + computer.compute(); + println!{"{:?}", computer} + + assert_eq!{99, computer.mem[4]} + } + + #[test] + fn tc2() { + let mut computer = Computer::new(); + let mem = vec![1101,100,-1,4,0]; + mem.iter().for_each(|&n| computer.push(n)); + println!{"{:?}", computer} + computer.compute(); + println!{"{:?}", computer} + + assert_eq!{99, computer.mem[4]} + } +} +