/ Rust / 2024 / 08.rs
08.rs
 1  #![feature(test)]
 2  
 3  use std::iter::successors;
 4  
 5  use num::Integer;
 6  use rustc_hash::{FxHashMap, FxHashSet};
 7  
 8  type Input = Vec<Vec<u8>>;
 9  type Position = (usize, usize);
10  
11  fn setup(input: &str) -> Input {
12      input
13          .trim()
14          .lines()
15          .map(|line| line.bytes().collect())
16          .collect()
17  }
18  
19  fn solve<I>(input: &Input, antinode_positions: impl Fn(Position, Position) -> I) -> usize
20  where
21      I: Iterator<Item = Position>,
22  {
23      let mut frequency_map = FxHashMap::<_, Vec<_>>::default();
24      for (y, row) in input.iter().enumerate() {
25          for (x, &c) in row.iter().enumerate() {
26              if c != b'.' {
27                  frequency_map.entry(c).or_default().push((x, y));
28              }
29          }
30      }
31  
32      let mut antinodes = FxHashSet::default();
33      for antennas in frequency_map.values() {
34          for (i, &a) in antennas.iter().enumerate() {
35              for &b in &antennas[..i] {
36                  antinodes.extend(antinode_positions(a, b));
37              }
38          }
39      }
40  
41      antinodes.len()
42  }
43  
44  fn part1(input: &Input) -> usize {
45      solve(input, |(x1, y1), (x2, y2)| {
46          let (x1, y1, x2, y2) = (x1 as isize, y1 as isize, x2 as isize, y2 as isize);
47          let (dx, dy) = (x2 - x1, y2 - y1);
48          [(x1 - dx, y1 - dy), (x2 + dx, y2 + dy)]
49              .into_iter()
50              .flat_map(|(x, y)| Some((x.try_into().ok()?, y.try_into().ok()?)))
51              .filter(|&(x, y)| x < input[0].len() && y < input.len())
52      })
53  }
54  
55  fn part2(input: &Input) -> usize {
56      let on_grid = |(x, y): &(isize, isize)| {
57          (0..input[0].len() as _).contains(x) && (0..input.len() as _).contains(y)
58      };
59      solve(input, |(x1, y1), (x2, y2)| {
60          let (x1, y1, x2, y2) = (x1 as isize, y1 as isize, x2 as isize, y2 as isize);
61          let (dx, dy) = (x2 - x1, y2 - y1);
62          let gcd = dx.abs().gcd(&dy.abs());
63          let (dx, dy) = (dx / gcd, dy / gcd);
64  
65          successors(Some((x1, y1)), move |&(x, y)| {
66              Some((x + dx, y + dy)).filter(on_grid)
67          })
68          .chain(successors(Some((x2, y2)), move |&(x, y)| {
69              Some((x - dx, y - dy)).filter(on_grid)
70          }))
71          .map(|(x, y)| (x as _, y as _))
72      })
73  }
74  
75  aoc::main!(2024, 8, ex: 1);