use std::cmp; use std::convert::Infallible; use std::str::FromStr; const SIZE: usize = 1000; #[derive(Debug)] struct Line { pub a: (u32, u32), pub b: (u32, u32), } fn part1(input: &[Line]) { let mut map = [[0; SIZE]; SIZE]; for line in input { line.cast_vh(&mut map); } let num_intersections = map.iter().flatten().filter(|&n| *n >= 2).count(); println!("Solution part 1: {}", num_intersections); } fn part2(input: &[Line]) { let mut map = [[0; SIZE]; SIZE]; for line in input { line.cast_vh(&mut map); line.cast_diag(&mut map); } let num_intersections = map.iter().flatten().filter(|&n| *n >= 2).count(); println!("Solution part 2: {}", num_intersections); } pub fn run(input: Vec) { let lines: Vec = input.iter().map(|s| Line::from_str(s).unwrap()).collect(); part1(&lines); part2(&lines); } impl Line { pub fn is_horizontal(&self) -> bool { self.a.1 == self.b.1 } pub fn is_vertical(&self) -> bool { self.a.0 == self.b.0 } pub fn cast_vh(&self, onto: &mut [[u8; SIZE]]) { if self.is_horizontal() { let start = cmp::min(self.a.0, self.b.0); let end = cmp::max(self.a.0, self.b.0); for x in start..=end { onto[self.a.1 as usize][x as usize] += 1; } } else if self.is_vertical() { let start = cmp::min(self.a.1, self.b.1); let end = cmp::max(self.a.1, self.b.1); for y in start..=end { onto[y as usize][self.a.0 as usize] += 1; } } } pub fn cast_diag(&self, onto: &mut [[u8; SIZE]]) { if self.is_horizontal() || self.is_vertical() { return; } // We know all other lines are 45 deg let mut dir = (0, 0); let len: i32 = if self.a.0 < self.b.0 { dir.0 = 1; (self.b.0 - self.a.0) as i32 } else if self.a.0 > self.b.0 { dir.0 = -1; (self.a.0 - self.b.0) as i32 } else { panic!("line is unexpectedly vertical!"); }; if self.a.1 < self.b.1 { dir.1 = 1; } else if self.a.1 > self.b.1 { dir.1 = -1; } else { panic!("line is unexpectedly horizontal!"); } for i in 0..=len { onto[(self.a.1 as i32 + (i * dir.1)) as usize] [(self.a.0 as i32 + (i * dir.0)) as usize] += 1; } } } impl FromStr for Line { type Err = Infallible; fn from_str(s: &str) -> Result { let parse_point = |s: &str| { let nums: Vec = s.split(',').map(|s| s.parse().unwrap()).collect(); assert_eq!(nums.len(), 2); (nums[0], nums[1]) }; let points: Vec<(u32, u32)> = s.split(" -> ").map(|s| parse_point(s)).collect(); assert_eq!(points.len(), 2); Ok(Line { a: points[0], b: points[1], }) } }