2021 day5/rust: use iterator to expand line points
This commit is contained in:
parent
83b9b79a28
commit
fff3899ae9
1 changed files with 52 additions and 21 deletions
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue