diff options
author | cos <cos> | 2019-12-07 23:09:12 +0100 |
---|---|---|
committer | cos <cos> | 2019-12-07 23:09:16 +0100 |
commit | edface94833462d5ccb3496ed631b2d3815646ec (patch) | |
tree | db4fe081453ae3583ac8f4560ca3163cef7d76fa /2019/rust/day07/src | |
parent | 9973aaf401649c6ffd3d14295ce6dd9e9e63d159 (diff) | |
download | adventofcode-edface94833462d5ccb3496ed631b2d3815646ec.zip |
Add day07, 2019
Solution search is implemented as shell scripts. Ugly and
fragile, but it got the task done.
Diffstat (limited to '2019/rust/day07/src')
-rw-r--r-- | 2019/rust/day07/src/main.rs | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/2019/rust/day07/src/main.rs b/2019/rust/day07/src/main.rs new file mode 100644 index 0000000..98b02ce --- /dev/null +++ b/2019/rust/day07/src/main.rs @@ -0,0 +1,195 @@ +use std::env; +use std::fs; +use std::io::{self, BufRead}; + +type BusWidth = i32; +type IOType = i32; +type IOData = Vec<IOType>; + +fn read_program(filename: &str) -> Vec<BusWidth> { + let contents = fs::read_to_string(filename) + .expect(filename); + + contents.split(',').map(|v| { + v.trim_end().parse().unwrap() + }).collect() +} + +#[derive(Debug)] +enum Arithm { + Add, + Mul, + LessThan, + Equals, +} + +#[derive(Debug)] +enum IO { + In, + Out, +} + +#[derive(Debug)] +enum Jmp { + JmpTrue, + JmpFalse, +} + +#[derive(Debug, PartialEq)] +enum ParameterMode { + Position, + Immediate, +} + +fn arithm(op:Arithm, ip:usize, modes:Vec<ParameterMode>, memory:&mut Vec<BusWidth>) { + if modes[2] == ParameterMode::Immediate { + panic!("Instruction can not store in immediate mode parameter. (IP: {})", ip); + } + let params:Vec<usize> = (0..=2).map(|n| match &modes[n] { + ParameterMode::Position => memory[ip + n + 1] as usize, + ParameterMode::Immediate => ip + n + 1, + }).collect(); + let left = params[0]; + let right = params[1]; + let result = params[2]; + + match op { + Arithm::Add => memory[result] = memory[left] + memory[right], + Arithm::Mul => memory[result] = memory[left] * memory[right], + Arithm::LessThan => memory[result] = if memory[left] < memory[right] { 1 } else { 0 }, + Arithm::Equals => memory[result] = if memory[left] == memory[right] { 1 } else { 0 }, + } +} + +fn jmp(op:Jmp, ip:usize, modes:Vec<ParameterMode>, memory:&mut Vec<BusWidth>) -> usize { + let params:Vec<usize> = (0..=2).map(|n| match &modes[n] { + ParameterMode::Position => memory[ip + n + 1] as usize, + ParameterMode::Immediate => ip + n + 1, + }).collect(); + let value = params[0]; + let address = params[1]; + + match op { + Jmp::JmpTrue => (if memory[value] != 0 { memory[address] as usize } else { ip + 3 }), + Jmp::JmpFalse => (if memory[value] == 0 { memory[address] as usize } else { ip + 3 }), + } +} + +fn io(op: IO, ip: usize, modes: Vec<ParameterMode>, memory:&mut Vec<BusWidth>, input:&mut IOData, + output:&mut IOData, var_io: bool) +{ + let stdin = io::stdin(); + + match op { + IO::In => { + let address = match &modes[0] { + ParameterMode::Position => memory[ip + 1] as usize, + ParameterMode::Immediate => + panic!("Cannot store input in immediate mode parameter. (IP: {})", ip), + }; + + match var_io { + false => { + let invalue = stdin.lock().lines().next().map(|s| { + match s { + Ok(s) => Some(s.trim_end().trim_start().parse::<BusWidth>().unwrap()), + _ => None, + } + }); + match invalue { + Some(v) => memory[address] = v.unwrap() as BusWidth, + _ => {}, + }; + }, + true => { + memory[address] = input.remove(0) as BusWidth; + }, + } + + }, + IO::Out => { + let o = match &modes[0] { + ParameterMode::Position => memory[memory[ip + 1] as usize], + ParameterMode::Immediate => memory[ip + 1], + }; + println!("{}", o); + if var_io { + output.push(o as IOType); + } + }, + } +} + +fn intcode<F>(mut memory:Vec<BusWidth>, mut input: &mut IOData, mut output:&mut IOData, + f: F, var_io: bool) where +F: Fn(&mut Vec<BusWidth>, &mut IOData, &mut IOData) +{ + let mut ip = 0; + + while ip < memory.len() { + + let op = memory[ip] % 100; + let modes:Vec<ParameterMode> = (2..=4).map(|e| memory[ip] / 10i32.pow(e) as BusWidth % 10) + .map(|n| match n { + 0 => ParameterMode::Position, + 1 => ParameterMode::Immediate, + p => panic!("Invalid parameter mode {} at IP: {}", p, ip), + }).collect(); + match op { + 1 => { arithm(Arithm::Add, ip, modes, &mut memory); ip += 4 }, + 2 => { arithm(Arithm::Mul, ip, modes, &mut memory); ip += 4 }, + 7 => { arithm(Arithm::LessThan, ip, modes, &mut memory); ip += 4 }, + 8 => { arithm(Arithm::Equals, ip, modes, &mut memory); ip += 4 }, + 3 => { io(IO::In, ip, modes, &mut memory, &mut input, &mut output, var_io); ip += 2 }, + 4 => { io(IO::Out, ip, modes, &mut memory, &mut input, &mut output, var_io); ip += 2 }, + 5 => { ip = jmp(Jmp::JmpTrue, ip, modes, &mut memory); }, + 6 => { ip = jmp(Jmp::JmpFalse, ip, modes, &mut memory); }, + 99 => break, + op => panic!("Invalid operation {} at IP: {}", op, ip), + } + + if var_io { + f(&mut memory, &mut input, &mut output); + } + } +} + +fn func(_memory:&mut Vec<BusWidth>, input:&mut IOData, output:&mut IOData) { + if output.len() > 0 && input.len() > 0 { + let v = output.remove(0); + input.insert(1, v); + } +} + +fn main() { + let args: Vec<String> = env::args().collect(); + + let mut opts = getopts::Options::new(); + opts.reqopt("m", "mode", "Mode of IO operations", "[arg|stdio]"); + opts.reqopt("p", "program", "File to load program from", "FILE"); + let matches = match opts.parse(&args[1..]) { + Ok(m) => { m } + Err(f) => { panic!(f.to_string()) } + }; + let program:String = matches.opt_str("program").unwrap(); + let mode = matches.opt_str("mode").unwrap(); + let memory = read_program(&program); + + if mode == "arg" { + let mut input:IOData = matches.free[0].split(",").map(|v| { + let i = v.trim_end().parse().unwrap(); + i + }).collect(); + let mut output = Vec::new(); + while input.len() > 1 { + intcode(memory.clone(), &mut input, &mut output, &func, true); + } + } else if mode == "stdio" { + let mut input = vec![]; + let mut output = vec![]; + + intcode(memory.clone(), &mut input, &mut output, &func, false); + } else { + panic!("Unknown mode: {}", mode); + } +} |