Compare commits

..

3 commits

View file

@ -1,6 +1,5 @@
#![warn(clippy::pedantic)] #![warn(clippy::pedantic)]
use std::{ use std::{
collections::HashMap,
convert::Infallible, convert::Infallible,
io::{stdin, BufRead}, io::{stdin, BufRead},
str::FromStr, str::FromStr,
@ -18,27 +17,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()
} }
} }
@ -57,15 +37,66 @@ impl FromStr for Line {
} }
} }
struct LinePoints {
pos: Vector2D<isize>,
step: Vector2D<isize>,
points_left: usize,
}
impl LinePoints {
fn new(line: &Line) -> Self {
let start = line.start.as_isizes();
let end = line.end.as_isizes();
let delta = end - start;
let step = Vector2D::new(delta.x.signum(), delta.y.signum());
let len = usize::max(delta.x.unsigned_abs(), delta.y.unsigned_abs());
Self {
pos: start,
step,
points_left: len + 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;
self.pos += self.step;
self.points_left -= 1;
Some(current.as_usizes())
}
}
fn count_overlaps<'a>(it: impl IntoIterator<Item = &'a Line>) -> usize { fn count_overlaps<'a>(it: impl IntoIterator<Item = &'a Line>) -> usize {
let counts: HashMap<(usize, usize), usize> = let points: Vec<(usize, usize)> = it
it.into_iter() .into_iter()
.flat_map(Line::expand) .flat_map(Line::expand)
.fold(HashMap::new(), |mut map, point| { .map(Into::into)
*map.entry(point.into()).or_default() += 1; .collect();
map
}); let (max_x, max_y) = points.iter().fold((0, 0), |(acc_x, acc_y), &(x, y)| {
counts.into_iter().filter(|&(_k, v)| v >= 2).count() (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
} }
fn main() { fn main() {