From b3d1ec28594260c667a58ce81be5098a642f5c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20S=C5=82adek?= Date: Sun, 8 Dec 2024 17:26:12 +0100 Subject: [PATCH] feat(08/2024): solve first part --- readme.md | 19 ++++---- src/solutions/year2024/day08.rs | 78 +++++++++++++++++++++++++++++++-- src/utils/grid.rs | 56 +++++++++++++++++++++++ src/utils/point.rs | 10 ++++- 4 files changed, 149 insertions(+), 14 deletions(-) diff --git a/readme.md b/readme.md index 6272911..9326579 100644 --- a/readme.md +++ b/readme.md @@ -9,15 +9,16 @@ # 2024 -| Day | Solved | Part 1 time (ms) | Part 2 time (ms) | -|--------------------------------------------------------------|:------:|-----------------:|-----------------:| -| [Day 1: Historian Hysteria](src/solutions/year2024/day01.rs) | ⭐⭐ | 0.221 | 0.219 | -| [Day 2: Red-Nosed Reports](src/solutions/year2024/day02.rs) | ⭐⭐ | 0.508 | 0.853 | -| [Day 3: Mull It Over](src/solutions/year2024/day03.rs) | ⭐⭐ | 1.680 | 0.959 | -| [Day 4: Ceres Search](src/solutions/year2024/day04.rs) | ⭐⭐ | 8.620 | 6.918 | -| [Day 5: Print Queue](src/solutions/year2024/day05.rs) | ⭐⭐ | 3.151 | 11.874 | -| [Day 6: Guard Gallivant](src/solutions/year2024/day06.rs) | ⭐ | 8.738 | | -| [Day 7: Bridge Repair](src/solutions/year2024/day07.rs) | ⭐⭐ | 1.198 | 219.754 | +| Day | Solved | Part 1 time (ms) | Part 2 time (ms) | +|-----------------------------------------------------------------|:------:|-----------------:|-----------------:| +| [Day 1: Historian Hysteria](src/solutions/year2024/day01.rs) | ⭐⭐ | 0.221 | 0.219 | +| [Day 2: Red-Nosed Reports](src/solutions/year2024/day02.rs) | ⭐⭐ | 0.508 | 0.853 | +| [Day 3: Mull It Over](src/solutions/year2024/day03.rs) | ⭐⭐ | 1.680 | 0.959 | +| [Day 4: Ceres Search](src/solutions/year2024/day04.rs) | ⭐⭐ | 8.620 | 6.918 | +| [Day 5: Print Queue](src/solutions/year2024/day05.rs) | ⭐⭐ | 3.151 | 11.874 | +| [Day 6: Guard Gallivant](src/solutions/year2024/day06.rs) | ⭐ | 8.738 | | +| [Day 7: Bridge Repair](src/solutions/year2024/day07.rs) | ⭐⭐ | 1.198 | 219.754 | +| [Day 8: Resonant Collinearity](src/solutions/year2024/day08.rs) | ⭐ | 0.883 | | # 2023 diff --git a/src/solutions/year2024/day08.rs b/src/solutions/year2024/day08.rs index bd81fe7..44611e7 100644 --- a/src/solutions/year2024/day08.rs +++ b/src/solutions/year2024/day08.rs @@ -1,10 +1,29 @@ use crate::solutions::Solution; +use crate::utils::grid::Grid; +use crate::utils::point::Point; +use itertools::Itertools; pub struct Day08; impl Solution for Day08 { - fn part_one(&self, _input: &str) -> String { - String::from('0') + fn part_one(&self, input: &str) -> String { + let grid: Grid = Grid::from(input); + let surface_range = grid.surface_range(); + + grid.elements_with_points() + .iter() + .filter(|(element, _)| **element != '.') + .flat_map(|(_, points)| { + points + .iter() + .combinations(2) + .flat_map(|pair| self.antinodes(*pair[0], *pair[1])) + .collect::>() + }) + .filter(|p| surface_range.contains(*p)) + .unique() + .count() + .to_string() } fn part_two(&self, _input: &str) -> String { @@ -12,15 +31,66 @@ impl Solution for Day08 { } } +impl Day08 { + fn antinodes(&self, p1: Point, p2: Point) -> Vec { + let diff = p1 - p2; + + vec![p1 + diff, p1 - diff, p2 + diff, p2 - diff] + .into_iter() + .filter(|p| *p != p1 && *p != p2) + .collect() + } +} + #[cfg(test)] mod tests { use crate::solutions::year2024::day08::Day08; use crate::solutions::Solution; + use crate::utils::grid::Grid; + use itertools::Itertools; - const EXAMPLE: &str = r#""#; + const EXAMPLE: &str = r#"............ +........0... +.....0...... +.......0.... +....0....... +......A..... +............ +............ +........A... +.........A.. +............ +............"#; #[test] fn part_one_example_test() { - assert_eq!("0", Day08.part_one(EXAMPLE)); + assert_eq!("14", Day08.part_one(EXAMPLE)); + } + + #[test] + fn antinodes() { + const GRID: &str = r#".......... +...#...... +.......... +....a..... +.......... +.....a.... +.......... +......#... +.......... +.........."#; + + let grid: Grid = Grid::from(GRID); + let elements = grid.elements_with_points(); + + let (p1, p2) = elements.get(&'a').unwrap().iter().collect_tuple().unwrap(); + + let mut result = Day08.antinodes(*p1, *p2); + let mut expected = elements.get(&'#').unwrap().to_vec(); + + result.sort(); + expected.sort(); + + assert_eq!(expected, result); } } diff --git a/src/utils/grid.rs b/src/utils/grid.rs index 9077894..1766446 100644 --- a/src/utils/grid.rs +++ b/src/utils/grid.rs @@ -6,6 +6,7 @@ use itertools::Itertools; use std::collections::{BTreeMap, HashMap}; use std::fmt; use std::fmt::Display; +use std::hash::Hash; #[derive(Debug, Clone)] pub struct Grid { @@ -266,6 +267,27 @@ where self.columns_range = Self::calculate_columns_range(&self.cells); self.rows_range = Self::calculate_rows_range(&self.cells) } + + pub fn elements_with_points(&self) -> HashMap> + where + T: Eq + Hash + Clone, + { + let mut elements: HashMap> = HashMap::new(); + let surface_range = self.surface_range(); + + for x in surface_range.columns().iter() { + for y in surface_range.rows().iter() { + let element = self.get(x, y).unwrap(); + + elements + .entry(element.clone()) + .or_default() + .push(Point::new(x, y)); + } + } + + elements + } } impl Display for Grid @@ -423,6 +445,40 @@ mod tests { assert_eq!("..\nAB\n..\nCD\n..\n", grid.to_string()); } + #[test] + fn elements_with_points() { + const GRID: &str = r#"..... +..a.b +a..a. +..... +....a"#; + + let mut expected: HashMap> = HashMap::new(); + expected.insert( + 'a', + vec![ + Point::new(2, 1), + Point::new(0, 2), + Point::new(3, 2), + Point::new(4, 4), + ], + ); + expected.insert('b', vec![Point::new(4, 1)]); + + let grid: Grid = Grid::from(GRID); + let mut result = grid.elements_with_points(); + result.remove(&'.'); + + for value in expected.values_mut() { + value.sort(); + } + for value in result.values_mut() { + value.sort(); + } + + assert_eq!(expected, result); + } + fn grid() -> Grid { let mut hash_map: HashMap = HashMap::new(); hash_map.insert(Point::new(0, 0), 'A'); diff --git a/src/utils/point.rs b/src/utils/point.rs index e61fbaa..5aaac30 100644 --- a/src/utils/point.rs +++ b/src/utils/point.rs @@ -4,7 +4,7 @@ use crate::utils::direction::Direction::{ }; use crate::utils::vector::Vector; use std::fmt::{Display, Formatter}; -use std::ops::{Add, Mul, Sub}; +use std::ops::{Add, Mul, Neg, Sub}; #[derive(Debug, PartialEq, Copy, Clone, Eq, Hash, Ord, PartialOrd)] pub struct Point { @@ -137,6 +137,14 @@ impl Mul for Point { } } +impl Neg for Point { + type Output = Point; + + fn neg(self) -> Self::Output { + Self::new(-self.x, -self.y) + } +} + #[cfg(test)] mod tests { use crate::utils::direction::Direction;