diff --git a/Cargo.lock b/Cargo.lock index 0256ee8..dc1a1e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ name = "aoc2024" version = "0.1.0" dependencies = [ + "gcd", "itertools", "regex", ] @@ -25,6 +26,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "itertools" version = "0.14.0" diff --git a/Cargo.toml b/Cargo.toml index 9c89a58..6a6d476 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] +gcd = "2.3.0" itertools = "0.14.0" regex = "1.12.2" diff --git a/src/day8.rs b/src/day8.rs index e0da849..e94220c 100644 --- a/src/day8.rs +++ b/src/day8.rs @@ -1,5 +1,10 @@ -use std::{collections::{HashMap, HashSet}, convert::Infallible, str::FromStr}; +use std::{ + collections::{HashMap, HashSet}, + convert::Infallible, + str::FromStr, +}; +use gcd::Gcd; use itertools::Itertools; pub fn day8_part1(input: &str) -> String { @@ -9,17 +14,43 @@ pub fn day8_part1(input: &str) -> String { } pub fn day8_part2(input: &str) -> String { - todo!() + let city: City = input.parse().unwrap(); + let antinodes: HashSet = city.resonant_antinodes().collect(); + antinodes.len().to_string() } fn antinodes(antenna1: Point, antenna2: Point) -> (Option, Option) { let distance: Vector2 = (antenna1, antenna2).into(); let antinode1 = antenna2 + distance; let antinode2 = antenna1 - distance; - dbg!(antenna1, antenna2, distance, antinode1, antinode2); (antinode1, antinode2) } +fn resonant_antinodes(antenna1: Point, antenna2: Point, width: usize, height: usize) -> Vec { + let distance: Vector2 = (antenna1, antenna2).into(); + let distance = distance.simplified(); + let mut last_antinode = antenna1; + let mut antinodes = vec![last_antinode]; + while let Some(next_antinode) = last_antinode + distance { + if next_antinode.row >= height || next_antinode.col >= width { + break; + } else { + antinodes.push(next_antinode); + last_antinode = next_antinode; + } + } + let mut last_antinode = antenna1; + while let Some(next_antinode) = last_antinode - distance { + if next_antinode.row >= height || next_antinode.col >= width { + break; + } else { + antinodes.push(next_antinode); + last_antinode = next_antinode; + } + } + antinodes +} + #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] struct Point { row: usize, @@ -74,6 +105,20 @@ impl From<(Point, Point)> for Vector2 { } } +impl Vector2 { + fn simplified(&self) -> Self { + let mut retval = *self; + let pos_col_distance: usize = retval.col_distance.unsigned_abs(); + let pos_row_distance: usize = retval.row_distance.unsigned_abs(); + let gcd = pos_col_distance.gcd(pos_row_distance); + if gcd != 1 { + retval.col_distance /= gcd as isize; + retval.row_distance /= gcd as isize; + } + retval + } +} + #[derive(Debug)] struct City { width: usize, @@ -116,12 +161,11 @@ impl City { retval.into_values().collect() } fn antenna_pairs(&self) -> impl Iterator { - let ap: Vec<(Point, Point)> = self.antenna_groups + self + .antenna_groups .iter() .flat_map(|group| group.iter().combinations(2)) - .map(|combination| (*combination[0], *combination[1])).collect(); - dbg!(&ap); - ap.into_iter() + .map(|combination| (*combination[0], *combination[1])) } fn antinodes(&self) -> impl Iterator { self.antenna_pairs() @@ -130,4 +174,9 @@ impl City { .flatten() .filter(|p| p.row < self.height && p.col < self.width) } + fn resonant_antinodes(&self) -> impl Iterator { + self.antenna_pairs() + .flat_map(|(from, to)| resonant_antinodes(from, to, self.width, self.height)) + .filter(|p| p.row < self.height && p.col < self.width) + } } diff --git a/src/lib.rs b/src/lib.rs index b1d16d2..9b174dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -361,6 +361,13 @@ mod tests { // assert!(result.parse::().unwrap() < 414); //too high assert_eq!(result, "369"); } + #[test] + fn day8_part2_test() { + let test_result = day8::day8_part2(include_str!("../input/day8.test.txt")); + assert_eq!(test_result, "34"); + let result = day8::day8_part2(include_str!("../input/day8.txt")); + assert_eq!(result, "1169"); + } #[test] fn day7_part1_test() {