2021 day5/rust: use iterator to expand line points

This commit is contained in:
Xiretza 2021-12-05 11:51:33 +01:00
parent c63c23c252
commit 5067c96550

View file

@ -1,5 +1,7 @@
#![feature(int_abs_diff)]
#![warn(clippy::pedantic)] #![warn(clippy::pedantic)]
use std::{ use std::{
cmp::Ordering,
convert::Infallible, convert::Infallible,
io::{stdin, BufRead}, io::{stdin, BufRead},
str::FromStr, str::FromStr,
@ -17,27 +19,8 @@ impl Line {
self.start.x == self.end.x || self.start.y == self.end.y self.start.x == self.end.x || self.start.y == self.end.y
} }
pub fn expand(&self) -> Vec<Vector2D<usize>> { pub fn expand(&self) -> impl Iterator<Item = Vector2D<usize>> {
let delta = self.end.as_isizes() - self.start.as_isizes(); LinePoints::new(self)
#[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()
} }
} }
@ -56,6 +39,54 @@ impl FromStr for Line {
} }
} }
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)
}
}
fn count_overlaps<'a>(it: impl IntoIterator<Item = &'a Line>) -> usize { fn count_overlaps<'a>(it: impl IntoIterator<Item = &'a Line>) -> usize {
let points: Vec<(usize, usize)> = it let points: Vec<(usize, usize)> = it
.into_iter() .into_iter()