diff --git a/2021/day5/day5_rs/Cargo.toml b/2021/day5/day5_rs/Cargo.toml new file mode 100644 index 0000000..df8c0bf --- /dev/null +++ b/2021/day5/day5_rs/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day5_rs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +vector2d = "2.2.0" diff --git a/2021/day5/day5_rs/src/main.rs b/2021/day5/day5_rs/src/main.rs new file mode 100644 index 0000000..5783430 --- /dev/null +++ b/2021/day5/day5_rs/src/main.rs @@ -0,0 +1,83 @@ +#![warn(clippy::pedantic)] +use std::{ + collections::HashMap, + convert::Infallible, + io::{stdin, BufRead}, + str::FromStr, +}; +use vector2d::Vector2D; + +#[derive(Copy, Clone, Debug)] +struct Line { + start: Vector2D, + end: Vector2D, +} + +impl Line { + pub fn is_straight(&self) -> bool { + self.start.x == self.end.x || self.start.y == self.end.y + } + + pub fn expand(&self) -> Vec> { + let delta = self.end.as_isizes() - self.start.as_isizes(); + + #[allow(clippy::if_not_else)] + let len = if delta.x != 0 { + delta.x.abs() + } else if delta.y != 0 { + delta.y.abs() + } else { + unreachable!() + }; + + let step = delta / len; + + (0..=len) + .scan(self.start, |acc, _| { + let prev = *acc; + *acc = (acc.as_isizes() + step).as_usizes(); + Some(prev) + }) + .collect() + } +} + +impl FromStr for Line { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + let parts: Vec<_> = s.split(' ').collect(); + let start: Vec<_> = parts[0].split(',').map(|n| n.parse().unwrap()).collect(); + let end: Vec<_> = parts[2].split(',').map(|n| n.parse().unwrap()).collect(); + + Ok(Line { + start: Vector2D::new(start[0], start[1]), + end: Vector2D::new(end[0], end[1]), + }) + } +} + +fn count_overlaps<'a>(it: impl IntoIterator) -> usize { + let counts: HashMap<(usize, usize), usize> = + it.into_iter() + .flat_map(Line::expand) + .fold(HashMap::new(), |mut map, point| { + *map.entry(point.into()).or_default() += 1; + map + }); + counts.into_iter().filter(|&(_k, v)| v >= 2).count() +} + +fn main() { + let lines: Vec = stdin() + .lock() + .lines() + .map(|s| s.unwrap().parse().unwrap()) + .collect(); + + println!( + "{}", + count_overlaps(lines.iter().filter(|line| line.is_straight())) + ); + println!("{}", count_overlaps(&lines)); +}