diff --git a/Cargo.toml b/Cargo.toml index a57a67e..d8be311 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,6 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] - [[bin]] name = "day1" path = "src/day1/main.rs" @@ -18,4 +16,12 @@ path = "src/day2/main.rs" [[bin]] name = "day3" -path = "src/day3/main.rs" \ No newline at end of file +path = "src/day3/main.rs" + +[[bin]] +name = "day4" +path = "src/day4/main.rs" + +[[bin]] +name = "day5" +path = "src/day5/main.rs" \ No newline at end of file diff --git a/src/day3/main.rs b/src/day3/main.rs index 4e780a0..358f424 100644 --- a/src/day3/main.rs +++ b/src/day3/main.rs @@ -4,120 +4,120 @@ use std::iter::FromIterator; #[derive(Debug)] enum Step { - Up(usize), - Down(usize), - Left(usize), - Right(usize), + Up(usize), + Down(usize), + Left(usize), + Right(usize), } impl Step { - fn draw(&self, map: &mut Vec, start: &mut Point) { - let mover: (i64, i64, &usize) = match self { - Step::Up(s) => (0, 1, s), - Step::Down(s) => (0, -1, s), - Step::Left(s) => (-1, 0, s), - Step::Right(s) => (1, 0, s), - }; - let (x, y, steps) = mover; - map.reserve(*steps); - for _ in 0..*steps { - start.x += x; - start.y += y; - map.push(start.clone()); - } - } + fn draw(&self, map: &mut Vec, start: &mut Point) { + let mover: (i64, i64, &usize) = match self { + Step::Up(s) => (0, 1, s), + Step::Down(s) => (0, -1, s), + Step::Left(s) => (-1, 0, s), + Step::Right(s) => (1, 0, s), + }; + let (x, y, steps) = mover; + map.reserve(*steps); + for _ in 0..*steps { + start.x += x; + start.y += y; + map.push(start.clone()); + } + } } impl From<&[u8]> for Step { - fn from(b: &[u8]) -> Self { - let steps: usize = b[0..] - .iter() - .filter(|i| **i >= b'0' && **i <= b'9') - .fold(0, |s, i| ((i - b'0') as usize + 10 * s)); - match b[0] { - b'U' => Step::Up(steps), - b'D' => Step::Down(steps), - b'L' => Step::Left(steps), - b'R' => Step::Right(steps), - _ => panic!("unknown directions"), - } - } + fn from(b: &[u8]) -> Self { + let steps: usize = b[0..] + .iter() + .filter(|i| **i >= b'0' && **i <= b'9') + .fold(0, |s, i| ((i - b'0') as usize + 10 * s)); + match b[0] { + b'U' => Step::Up(steps), + b'D' => Step::Down(steps), + b'L' => Step::Left(steps), + b'R' => Step::Right(steps), + _ => panic!("unknown directions"), + } + } } #[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)] struct Point { - x: i64, - y: i64, + x: i64, + y: i64, } impl Point { - fn dist_to_00(&self) -> u64 { - (self.x.abs() + self.y.abs()) as u64 - } + fn dist_to_00(&self) -> u64 { + (self.x.abs() + self.y.abs()) as u64 + } } impl From<(i64, i64)> for Point { - fn from(xy: (i64, i64)) -> Self { - Point { x: xy.0, y: xy.1 } - } + fn from(xy: (i64, i64)) -> Self { + Point { x: xy.0, y: xy.1 } + } } fn main() -> io::Result<()> { - let commands = load(); - let mut wires: Vec> = vec![]; - commands.iter().enumerate().for_each(|(_, wire)| { - let mut map = Vec::new(); - let mut p: Point = (0, 0).into(); - wire.iter().for_each(|step| { - step.draw(&mut map, &mut p); - }); - wires.push(map); - }); - let wire_sets: Vec> = wires - .iter() - .map(|wire| HashSet::from_iter(wire.iter())) - .collect(); - let closest = wire_sets[0] - .intersection(&wire_sets[1]) - .fold(None, |min, point| { - let dist = point.dist_to_00(); - match min { - None => Some(dist), - Some(min) => Some(if dist < min { dist } else { min }), - } - }) - .expect("no mataching points found"); - let shortest = wire_sets[0] - .intersection(&wire_sets[1]) - .map(|point| { - wires[0].iter().position(|p| p == *point).unwrap() - + wires[1].iter().position(|p| p == *point).unwrap() - + 2 - }) - .fold(None, |min, dist| { - Some(match min { - None => dist, - Some(d) => { - if dist < d { - dist - } else { - d - } - } - }) - }) - .expect("no matching points found"); - println!("closest: {}", closest); - println!("shortest: {}", shortest); - Ok(()) + let commands = load(); + let mut wires: Vec> = vec![]; + commands.iter().enumerate().for_each(|(_, wire)| { + let mut map = Vec::new(); + let mut p: Point = (0, 0).into(); + wire.iter().for_each(|step| { + step.draw(&mut map, &mut p); + }); + wires.push(map); + }); + let wire_sets: Vec> = wires + .iter() + .map(|wire| HashSet::from_iter(wire.iter())) + .collect(); + let closest = wire_sets[0] + .intersection(&wire_sets[1]) + .fold(None, |min, point| { + let dist = point.dist_to_00(); + match min { + None => Some(dist), + Some(min) => Some(if dist < min { dist } else { min }), + } + }) + .expect("no mataching points found"); + let shortest = wire_sets[0] + .intersection(&wire_sets[1]) + .map(|point| { + wires[0].iter().position(|p| p == *point).unwrap() + + wires[1].iter().position(|p| p == *point).unwrap() + + 2 + }) + .fold(None, |min, dist| { + Some(match min { + None => dist, + Some(d) => { + if dist < d { + dist + } else { + d + } + } + }) + }) + .expect("no matching points found"); + println!("closest: {}", closest); + println!("shortest: {}", shortest); + Ok(()) } fn load() -> Vec> { - let stdin = io::stdin(); - stdin - .lock() - .split(b'\n') - .filter_map(|i| i.ok()) - .map(|line| line.split(|b| *b == b',').map(|i| Step::from(i)).collect()) - .collect() + let stdin = io::stdin(); + stdin + .lock() + .split(b'\n') + .filter_map(|i| i.ok()) + .map(|line| line.split(|b| *b == b',').map(|i| Step::from(i)).collect()) + .collect() } diff --git a/src/day4/main.rs b/src/day4/main.rs new file mode 100644 index 0000000..a9fcc28 --- /dev/null +++ b/src/day4/main.rs @@ -0,0 +1,40 @@ +use std::io::{self}; + +fn main() -> io::Result<()> { + let count = (152085..670283) + .map(|i| i.to_string()) + .filter(|pass| { + let mut chars = pass.chars(); + let mut last = chars.next().unwrap(); + for char in chars { + if char < last { + return false; + } + last = char; + } + true + }) + .filter(|pass| { + let mut matches: Vec = vec![]; + let mut chars = pass.chars(); + let mut last = chars.next().unwrap(); + let mut matchlen = 1; + for char in chars { + if char == last { + matchlen += 1; + } else { + matches.push(matchlen); + matchlen = 1; + } + last = char; + } + matches.push(matchlen); + if let Some(_) = matches.iter().position(|i| *i == 2) { + return true; + } + false + }) + .count(); + println!("count: {}", count); + Ok(()) +} diff --git a/src/day5/main.rs b/src/day5/main.rs new file mode 100644 index 0000000..c91ebc7 --- /dev/null +++ b/src/day5/main.rs @@ -0,0 +1,298 @@ +use std::env; +use std::fs::File; +use std::io::{self, BufRead, BufReader, Write}; + +#[derive(Copy, Clone, Debug)] +enum Mode { + Position, + Immediate, +} + +impl Default for Mode { + fn default() -> Self { + Mode::Position + } +} + +impl From for Mode { + fn from(b: bool) -> Self { + match b { + false => Mode::Position, + true => Mode::Immediate, + } + } +} + +#[derive(Copy, Clone, Default, Debug)] +struct Modes { + a: Mode, + b: Mode, + c: Mode, +} + +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, + 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, + 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 a = i % 1000 >= 100; + let b = i % 10000 >= 1000; + let c = i > 10000; + let modes = (Mode::from(a), Mode::from(b), Mode::from(c)).into(); + ModedOpcode { + modes: modes, + op: Opcode::from(code), + } + } +} + +fn main() -> io::Result<()> { + println!("Hello, i am {}.", env::args().next().unwrap()); + let filename = env::args().nth(1).expect("provide file as first param"); + let computer = Computer::from(File::open(filename)?); + computer.clone().run(); + Ok(()) +} + +struct Computer { + pos: usize, + program: Vec, + modes: Modes, +} + +impl Clone for Computer { + fn clone(&self) -> Self { + Computer { + pos: 0, + program: self.program.clone(), + modes: Default::default(), + } + } +} + +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(); + program.into() + } +} + +impl From> for Computer { + fn from(program: Vec) -> Self { + Computer { + pos: 0, + program: program, + modes: Default::default(), + } + } +} + +impl Computer { + fn update(&mut self, u: Vec<(usize, i64)>) -> Computer { + let mut computer = self.clone(); + for (pos, val) in u { + computer.program[pos] = val; + } + computer + } + + fn run(&mut self) -> i64 { + loop { + let instruction = self.program[self.pos]; + let instruction = ModedOpcode::from(instruction); + self.modes = (&instruction).into(); + let advance = match (&instruction).into() { + 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::Halt => return self.program[0], + }; + self.pos += advance; + } + } + + fn get_a(&self) -> i64 { + let a = self.program[self.pos + 1]; + match self.modes.a { + Mode::Position => self.program[a as usize], + Mode::Immediate => a, + } + } + + fn set_a(&mut self, value: i64) { + let a = self.program[self.pos + 1]; + match self.modes.a { + Mode::Position => self.program[a as usize] = value, + Mode::Immediate => self.program[self.pos] = value, + } + } + + fn get_b(&self) -> i64 { + let b = self.program[self.pos + 2]; + match self.modes.b { + Mode::Position => self.program[b as usize], + Mode::Immediate => b, + } + } + + fn set_c(&mut self, value: i64) { + let c = self.program[self.pos + 3]; + match self.modes.c { + Mode::Position => self.program[c as usize] = value, + Mode::Immediate => self.program[self.pos] = 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 mut line = String::new(); + print!("input: "); + io::stdout().flush().expect("unable to flush output"); + io::stdin().lock().read_line(&mut line).expect("input failed"); + let value = line.trim().parse().expect("numeric input required"); + self.set_a(value); + 2 + } + + fn output(&mut self) -> usize { + println!("output: {}", 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 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn example1() { + let program: Vec = vec![1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50]; + assert_eq!(Computer::from(program).run(), 3500) + } + + #[test] + fn example2() { + let program: Vec = vec![1, 0, 0, 0, 99]; + assert_eq!(Computer::from(program).run(), 2) + } + + #[test] + fn example3() { + let program: Vec = vec![1, 1, 1, 4, 99, 5, 6, 0, 99]; + assert_eq!(Computer::from(program).run(), 30) + } +}