#![feature(int_abs_diff)] #![warn(clippy::pedantic)] use std::{ cmp::Ordering, 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) -> impl Iterator> { LinePoints::new(self) } } 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]), }) } } struct LinePoints { pos: Vector2D, 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; fn next(&mut self) -> Option { 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) -> 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)); }