use std::{collections::HashMap, str::FromStr}; use color_eyre::{ eyre::{eyre, Error}, Result, }; pub fn solve() -> Result<()> { let input_data = include_str!("../../data/day_05.txt").trim(); println!("Day 05 Part 1: {}", part_1(input_data)?); println!("Day 05 Part 2: {}", part_2(input_data)?); Ok(()) } #[derive(Debug)] struct Vector { a: (isize, isize), b: (isize, isize), } impl Vector { fn diagonal_coordinates(&self) -> Vec<(isize, isize)> { let x_coordinates = { let x_amount = (self.a.0 - self.b.0).abs(); if self.a.0 < self.b.0 { (0..=x_amount) .into_iter() .map(|x| self.a.0 + x) .collect::>() } else { (0..=x_amount) .into_iter() .map(|x| self.a.0 - x) .collect::>() } }; let y_coordinates = { let y_amount = (self.a.1 - self.b.1).abs(); if self.a.1 < self.b.1 { (0..=y_amount) .into_iter() .map(|x| self.a.1 + x) .collect::>() } else { (0..=y_amount) .into_iter() .map(|x| self.a.1 - x) .collect::>() } }; x_coordinates.into_iter().zip(y_coordinates).collect() } fn horizontal_coordinates(&self) -> Vec<(isize, isize)> { let y = self.a.1; let (x1, x2) = if self.a.0 < self.b.0 { (self.a.0, self.b.0) } else { (self.b.0, self.a.0) }; (x1..=x2).into_iter().map(|x| (x, y)).collect() } fn vertical_coordinates(&self) -> Vec<(isize, isize)> { let x = self.a.0; let (y1, y2) = if self.a.1 < self.b.1 { (self.a.1, self.b.1) } else { (self.b.1, self.a.1) }; (y1..=y2).into_iter().map(|y| (x, y)).collect() } } impl FromStr for Vector { type Err = Error; fn from_str(s: &str) -> Result { let numbers = s .replace(" -> ", ",") .split(",") .map(str::parse) .collect::, _>>()?; if numbers.len() == 4 { Ok(Self { a: (numbers[0], numbers[1]), b: (numbers[2], numbers[3]), }) } else { Err(eyre!("Invalid input: {}", s)) } } } fn part_1(input: &str) -> Result { let vectors = input .lines() .filter_map(|line| { if let Ok(vector) = Vector::from_str(line) { if vector.a.0 == vector.b.0 || vector.a.1 == vector.b.1 { return Some(vector); } } None }) .collect::>(); let mut travelled_coordinates = HashMap::<(isize, isize), isize>::new(); for vector in vectors { let coordinates = if vector.a.0 == vector.b.0 { vector.vertical_coordinates() } else { vector.horizontal_coordinates() }; for coordinate in coordinates { let amount = travelled_coordinates.entry(coordinate).or_default(); *amount += 1; } } Ok(count_result(travelled_coordinates)) } fn part_2(input: &str) -> Result { let vectors = input .lines() .map(str::parse) .collect::>>()?; let mut travelled_coordinates = HashMap::<(isize, isize), isize>::new(); for vector in vectors { let coordinates = if vector.a.0 == vector.b.0 { vector.vertical_coordinates() } else if vector.a.1 == vector.b.1 { vector.horizontal_coordinates() } else { vector.diagonal_coordinates() }; for coordinate in coordinates { let amount = travelled_coordinates.entry(coordinate).or_default(); *amount += 1; } } Ok(count_result(travelled_coordinates)) } fn count_result(coordinates: HashMap<(isize, isize), isize>) -> usize { coordinates .into_iter() .filter(|(_, amount)| amount >= &2) .count() }