#![warn(clippy::pedantic)] use std::{ 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 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 } 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)); }