Files
advent-of-code-2024-rust/src/day8.rs

140 lines
3.8 KiB
Rust

use std::collections::HashMap;
use itertools::Itertools;
#[cfg(test)]
use crate::util::read_file;
use crate::{day_solver::DaySolver, util::{Coord, Grid}};
pub struct Day8 {
map: Grid<char>
}
impl Day8 {
pub fn create(input: String) -> Self {
Day8 {
map: Grid::parse(input, None)
}
}
fn get_antennas_per_frequency(&self) -> HashMap<char, Vec<Coord<usize>>> {
let mut frequency_antennas: HashMap<char, Vec<Coord<usize>>> = HashMap::new();
for y in 0..self.map.height() {
for x in 0..self.map.width {
let cur = self.map.get(x, y);
let pos: Coord<usize> = Coord::new(x, y);
if cur != &'.' {
if let Some(ant_pos) = frequency_antennas.get_mut(cur) {
ant_pos.push(pos);
} else {
frequency_antennas.insert(cur.to_owned(), vec![pos]);
}
}
}
}
frequency_antennas
}
fn find_antinodes(&self, antennas: &Vec<Coord<usize>>) -> Vec<Coord<usize>> {
let mut antinodes = Vec::new();
for a in antennas {
for b in antennas {
if a == b {
continue;
}
let mut a_signed = a.as_signed();
let dist = a_signed.sub(&b.as_signed());
antinodes.push(a.to_owned());
while let Ok(antinode) = TryInto::<Coord<usize>>::try_into(a_signed.add(&dist)) {
if self.map.in_bounds(antinode.x, antinode.y) {
antinodes.push(antinode);
} else {
break;
}
a_signed = antinode.as_signed()
}
}
}
antinodes
}
}
impl DaySolver for Day8 {
fn solve_part1(&mut self) -> String {
let frequency_antennas = self.get_antennas_per_frequency();
frequency_antennas.iter()
.flat_map(|(_, antennas)| {
antennas.iter().flat_map(|a|
antennas.iter()
.filter_map(|b| if b.to_owned() == a.to_owned() {
None
} else {
let a_signed = a.as_signed();
let dist = a_signed.sub(&b.as_signed());
Some(a_signed.add(&dist))
})
)
})
.filter_map::<Coord<usize>, _>(|c| c.try_into().ok())
.filter(|c| self.map.in_bounds(c.x, c.y))
.unique()
// .map(|c| { println!("{:?}", c); c })
.count().to_string()
}
fn solve_part2(&mut self) -> String {
let frequency_antennas = self.get_antennas_per_frequency();
let antinodes = frequency_antennas.iter()
.flat_map(|(_, antennas)| self.find_antinodes(antennas))
.unique()
.collect::<Vec<Coord<usize>>>();
// let mut full_map = self.map.clone();
// antinodes.iter().for_each(|n| full_map.set(n.x, n.y, '#'));
// full_map.print();
antinodes
.len().to_string()
}
}
#[test]
fn test_part1() {
let mut day = Day8::create(read_file("input/day08_example.txt"));
assert_eq!("14", day.solve_part1());
}
#[test]
fn test_part1_basic() {
let sample = "..........
..........
..........
....a.....
..........
.....a....
..........
..........
..........
..........";
let mut day = Day8::create(sample.to_string());
assert_eq!("2", day.solve_part1());
}
#[test]
fn test_part2() {
let mut day = Day8::create(read_file("input/day08_example.txt"));
assert_eq!("34", day.solve_part2());
}