From e8894ad31ddeb6432b1e9ccd6e87bc94fdc85de8 Mon Sep 17 00:00:00 2001 From: Stefan Schwarz Date: Sun, 10 May 2020 20:22:35 +0200 Subject: [PATCH 1/3] day10 part1 --- Cargo.toml | 6 +- input10 | 24 +++++ src/day10/main.rs | 268 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 input10 create mode 100644 src/day10/main.rs diff --git a/Cargo.toml b/Cargo.toml index a5a2b2b..3ee5431 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,4 +32,8 @@ path = "src/day7/main.rs" [[bin]] name = "day9" -path = "src/day9/main.rs" \ No newline at end of file +path = "src/day9/main.rs" + +[[bin]] +name = "day10" +path = "src/day10/main.rs" \ No newline at end of file diff --git a/input10 b/input10 new file mode 100644 index 0000000..51520ab --- /dev/null +++ b/input10 @@ -0,0 +1,24 @@ +.###.#...#.#.##.#.####.. +.#....#####...#.######.. +#.#.###.###.#.....#.#### +##.###..##..####.#.####. +###########.#######.##.# +##########.#########.##. +.#.##.########.##...###. +###.#.##.#####.#.###.### +##.#####.##..###.#.##.#. +.#.#.#####.####.#..##### +.###.#####.#..#..##.#.## +########.##.#...######## +.####..##..#.###.###.#.# +....######.##.#.######.# +###.####.######.#....### +############.#.#.##.#### +##...##..####.####.#..## +.###.#########.###..#.## +#.##.#.#...##...#####..# +##.#..###############.## +##.###.#####.##.######.. +##.#####.#.#.##..####### +...#######.######...#### +#....#.#.#.####.#.#.#.## diff --git a/src/day10/main.rs b/src/day10/main.rs new file mode 100644 index 0000000..8cf7c01 --- /dev/null +++ b/src/day10/main.rs @@ -0,0 +1,268 @@ +use std::collections::{HashMap, HashSet}; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::ops::Sub; + +#[derive(Clone, Debug, PartialEq)] +enum Position { + Empty, + Astroid, +} + +impl From<&u8> for Position { + fn from(c: &u8) -> Self { + match c { + b'.' => Position::Empty, + b'#' => Position::Astroid, + _ => panic!("invalid input"), + } + } +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +struct XY { + x: isize, + y: isize, +} + +impl From<(usize, usize)> for XY { + fn from((x, y): (usize, usize)) -> Self { + XY { + x: x as isize, + y: y as isize, + } + } +} + +impl Sub for &XY { + type Output = XY; + fn sub(self, other: &XY) -> Self::Output { + let xy = XY { + x: self.x - other.x, + y: self.y - other.y, + }; + xy + } +} + +impl XY { + fn direction(&self) -> Self { + let d = gcd(self.y, self.x).abs(); + if d != 0 { + XY { + x: self.x / d, + y: self.y / d, + } + } else { + self.clone() + } + } +} + +struct MonitoringStation { + map: HashMap, + size_x: usize, + size_y: usize, +} + +impl MonitoringStation { + fn find(&self) -> (usize, XY) { + let mut best = (0, XY::from((0, 0))); + for x in 0..self.size_x { + for y in 0..self.size_y { + let root = XY::from((x, y)); + // we only can build on astroids + if *self.map.get(&root).unwrap() == Position::Empty { + continue; + } + let insight = self + .map + .iter() + // get direction to any of the astroids + .filter_map(|(xy, pos)| { + if *pos == Position::Empty { + return None; + } + let rel = xy - &root; + Some(rel.direction()) + }) + // and keep only one in each direction + .fold(HashSet::new(), |mut acc, xy| { + acc.insert(xy); + acc + }) + .len() + - 1; + if insight > best.0 { + best = (insight, root) + } + } + } + best + } +} + +impl From for MonitoringStation +where + T: BufRead, +{ + fn from(reader: T) -> Self { + let map: HashMap = HashMap::new(); + let mut size_y = 0; + let map = reader + .split(b'\n') + .enumerate() + .flat_map(|(y, line)| { + size_y += 1; + line.unwrap() + .iter() + .enumerate() + .map(|(x, c)| { + let xy = XY::from((x, y)); + let p = Position::from(c); + (xy, p) + }) + .collect::>() + }) + .fold(map, |mut map, (xy, p)| { + map.insert(xy.clone(), p.clone()); + map + }); + let size_x = map.iter().count() / size_y; + MonitoringStation { + map, + size_x, + size_y, + } + } +} + +fn main() -> Result<(), Box> { + let f = File::open("input10")?; + let reader = BufReader::new(f); + let best = MonitoringStation::from(reader).find(); + println!("best: {:?}", best); + Ok(()) +} + +fn gcd(x: isize, y: isize) -> isize { + let mut x = x; + let mut y = y; + while y != 0 { + let t = y; + y = x % y; + x = t; + } + x +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn example1() { + let reader = BufReader::new(".#..#\n.....\n#####\n....#\n...##".as_bytes()); + let (count, xy) = MonitoringStation::from(reader).find(); + assert_eq!(xy, XY { x: 3, y: 4 }); + assert_eq!(count, 8); + } + + #[test] + fn example2() { + let reader = BufReader::new( + " +......#.#. +#..#.#.... +..#######. +.#.#.###.. +.#..#..... +..#....#.# +#..#....#. +.##.#..### +##...#..#. +.#....####" + .trim() + .as_bytes(), + ); + let (count, xy) = MonitoringStation::from(reader).find(); + assert_eq!(xy, XY { x: 5, y: 8 }); + assert_eq!(count, 33); + } + + #[test] + fn example3() { + let reader = BufReader::new( + " +#.#...#.#. +.###....#. +.#....#... +##.#.#.#.# +....#.#.#. +.##..###.# +..#...##.. +..##....## +......#... +.####.###." + .trim() + .as_bytes(), + ); + let (count, xy) = MonitoringStation::from(reader).find(); + assert_eq!(xy, XY { x: 1, y: 2 }); + assert_eq!(count, 35); + } + + #[test] + fn example4() { + let reader = BufReader::new( + " +.#..#..### +####.###.# +....###.#. +..###.##.# +##.##.#.#. +....###..# +..#.#..#.# +#..#.#.### +.##...##.# +.....#.#.." + .trim() + .as_bytes(), + ); + let (count, xy) = MonitoringStation::from(reader).find(); + assert_eq!(xy, XY { x: 6, y: 3 }); + assert_eq!(count, 41); + } + + #[test] + fn example5() { + let reader = BufReader::new( + " +.#..##.###...####### +##.############..##. +.#.######.########.# +.###.#######.####.#. +#####.##.#.##.###.## +..#####..#.######### +#################### +#.####....###.#.#.## +##.################# +#####.##.###..####.. +..######..##.####### +####.##.####...##..# +.#####..#.######.### +##...#.##########... +#.##########.####### +.####.#.###.###.#.## +....##.##.###..##### +.#.#.###########.### +#.#.#.#####.####.### +###.##.####.##.#..##" + .trim() + .as_bytes(), + ); + let (count, xy) = MonitoringStation::from(reader).find(); + assert_eq!(xy, XY { x: 11, y: 13 }); + assert_eq!(count, 210); + } +} From b7025c1dc2ecf53bf0ed9f12bc84207edcd36149 Mon Sep 17 00:00:00 2001 From: Stefan Schwarz Date: Sun, 10 May 2020 20:34:13 +0200 Subject: [PATCH 2/3] maybe --- src/day10/main.rs | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/day10/main.rs b/src/day10/main.rs index 8cf7c01..23f70db 100644 --- a/src/day10/main.rs +++ b/src/day10/main.rs @@ -61,20 +61,15 @@ impl XY { struct MonitoringStation { map: HashMap, - size_x: usize, - size_y: usize, } impl MonitoringStation { fn find(&self) -> (usize, XY) { - let mut best = (0, XY::from((0, 0))); - for x in 0..self.size_x { - for y in 0..self.size_y { - let root = XY::from((x, y)); - // we only can build on astroids - if *self.map.get(&root).unwrap() == Position::Empty { - continue; - } + let best = (0, XY::from((0, 0))); + self.map + .iter() + .filter(|(_, pos)| **pos == Position::Astroid) + .map(|(root, _)| { let insight = self .map .iter() @@ -83,7 +78,7 @@ impl MonitoringStation { if *pos == Position::Empty { return None; } - let rel = xy - &root; + let rel = xy - root; Some(rel.direction()) }) // and keep only one in each direction @@ -93,12 +88,14 @@ impl MonitoringStation { }) .len() - 1; - if insight > best.0 { - best = (insight, root) + (insight, root) + }) + .fold(best, |acc, astroid| { + if astroid.0 > acc.0 { + return (astroid.0, astroid.1.clone()); } - } - } - best + acc + }) } } @@ -108,12 +105,10 @@ where { fn from(reader: T) -> Self { let map: HashMap = HashMap::new(); - let mut size_y = 0; let map = reader .split(b'\n') .enumerate() .flat_map(|(y, line)| { - size_y += 1; line.unwrap() .iter() .enumerate() @@ -128,12 +123,7 @@ where map.insert(xy.clone(), p.clone()); map }); - let size_x = map.iter().count() / size_y; - MonitoringStation { - map, - size_x, - size_y, - } + MonitoringStation { map } } } From 074d8df6c5d63320d67662ea1fda38920cf68f51 Mon Sep 17 00:00:00 2001 From: Stefan Schwarz Date: Mon, 11 May 2020 07:37:10 +0200 Subject: [PATCH 3/3] on the way to part2 --- src/day10/main.rs | 71 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/src/day10/main.rs b/src/day10/main.rs index 23f70db..1ca696e 100644 --- a/src/day10/main.rs +++ b/src/day10/main.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::{BufRead, BufReader}; @@ -45,6 +46,18 @@ impl Sub for &XY { } } +impl PartialOrd for XY { + fn partial_cmp(&self, other: &XY) -> Option { + self.angle().partial_cmp(&other.angle()) + } +} + +impl Ord for XY { + fn cmp(&self, other: &XY) -> Ordering { + self.angle().partial_cmp(&other.angle()).unwrap() + } +} + impl XY { fn direction(&self) -> Self { let d = gcd(self.y, self.x).abs(); @@ -57,13 +70,57 @@ impl XY { self.clone() } } + + fn angle(&self) -> f64 { + (self.y as f64).atan2(self.x as f64) * (180 as f64 / std::f64::consts::PI) + } } struct MonitoringStation { map: HashMap, + size_x: usize, + size_y: usize, } impl MonitoringStation { + fn laser(&self, root: &XY) -> impl Iterator + '_ { + let mut map: HashMap> = HashMap::new(); + map = self + .map + .iter() + .filter_map(|(xy, pos)| { + if *pos == Position::Empty { + return None; + } + let rel = xy - &root; + Some((xy, rel.direction())) + }) + .fold(map, |mut acc, (xy, dir)| { + acc.entry(dir).or_insert(vec![]).push(xy.clone()); + acc + }); + let mut angles = map.keys().cloned().collect::>(); + angles.sort(); + + let mut popped = true; + let mut cycles = 0; + while popped { + popped = false; + cycles += 1; + angles.iter().for_each(|xy| match map.get_mut(xy) { + Some(xy) => { + if let Some(xy) = xy.pop() { + popped = true; + println!("{:?}", xy) + } + } + None => (), + }); + } + println!("cycles: {}", cycles); + self.map.iter().map(|(xy, _)| xy.clone()) + } + fn find(&self) -> (usize, XY) { let best = (0, XY::from((0, 0))); self.map @@ -105,10 +162,12 @@ where { fn from(reader: T) -> Self { let map: HashMap = HashMap::new(); + let mut size_y = 0; let map = reader .split(b'\n') .enumerate() .flat_map(|(y, line)| { + size_y += 1; line.unwrap() .iter() .enumerate() @@ -123,15 +182,23 @@ where map.insert(xy.clone(), p.clone()); map }); - MonitoringStation { map } + let size_x = map.iter().count() / size_y; + MonitoringStation { + map, + size_x, + size_y, + } } } fn main() -> Result<(), Box> { let f = File::open("input10")?; let reader = BufReader::new(f); - let best = MonitoringStation::from(reader).find(); + let station = MonitoringStation::from(reader); + let best = station.find(); + let test = station.laser(&best.1).next(); println!("best: {:?}", best); + println!("test: {:?}", test); Ok(()) }