advent-of-code/2021/day5/day5_rs/src/main.rs

127 lines
3 KiB
Rust
Raw Normal View History

#![feature(int_abs_diff)]
2021-12-05 10:01:53 +01:00
#![warn(clippy::pedantic)]
use std::{
cmp::Ordering,
2021-12-05 10:01:53 +01:00
convert::Infallible,
io::{stdin, BufRead},
str::FromStr,
};
use vector2d::Vector2D;
#[derive(Copy, Clone, Debug)]
struct Line {
start: Vector2D<usize>,
end: Vector2D<usize>,
}
impl Line {
pub fn is_straight(&self) -> bool {
self.start.x == self.end.x || self.start.y == self.end.y
}
pub fn expand(&self) -> impl Iterator<Item = Vector2D<usize>> {
LinePoints::new(self)
2021-12-05 10:01:53 +01:00
}
}
impl FromStr for Line {
type Err = Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
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]),
})
}
}
struct LinePoints {
pos: Vector2D<usize>,
x_change: Ordering,
y_change: Ordering,
points_left: usize,
}
impl LinePoints {
fn new(line: &Line) -> Self {
let x_change = line.end.x.cmp(&line.start.x);
let y_change = line.end.y.cmp(&line.start.y);
let delta_x = line.end.x.abs_diff(line.start.x);
let delta_y = line.end.y.abs_diff(line.start.y);
Self {
pos: line.start,
x_change,
y_change,
points_left: usize::max(delta_x, delta_y) + 1,
}
}
}
impl Iterator for LinePoints {
type Item = Vector2D<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.points_left == 0 {
return None;
}
let current = self.pos;
match self.x_change {
Ordering::Less => self.pos.x -= 1,
Ordering::Greater => self.pos.x += 1,
Ordering::Equal => {}
}
match self.y_change {
Ordering::Less => self.pos.y -= 1,
Ordering::Greater => self.pos.y += 1,
Ordering::Equal => {}
}
self.points_left -= 1;
Some(current)
}
}
2021-12-05 10:01:53 +01:00
fn count_overlaps<'a>(it: impl IntoIterator<Item = &'a Line>) -> usize {
let points: Vec<(usize, usize)> = it
.into_iter()
.flat_map(Line::expand)
.map(Into::into)
.collect();
let (max_x, max_y) = points.iter().fold((0, 0), |(acc_x, acc_y), &(x, y)| {
(usize::max(acc_x, x), usize::max(acc_y, y))
});
let mut field = vec![vec![0_usize; max_y + 1]; max_x + 1];
let mut hits = 0;
for (x, y) in points {
let point = &mut field[x][y];
if *point == 1 {
hits += 1;
}
*point += 1;
}
hits
2021-12-05 10:01:53 +01:00
}
fn main() {
let lines: Vec<Line> = stdin()
.lock()
.lines()
.map(|s| s.unwrap().parse().unwrap())
.collect();
println!(
"{}",
count_overlaps(lines.iter().filter(|line| line.is_straight()))
);
println!("{}", count_overlaps(&lines));
}