Advent of Code solutions
1use std::collections::HashSet;
2
3use advent_core::{day_stuff, ex_for_day, Day};
4use utils::tiles;
5
6pub struct Day8;
7
8tiles!(Tile, [
9 '.' => Empty,
10], [
11 Antenna(char)
12], |c| {
13 Self::Antenna(c)
14});
15
16type Grid = utils::grid::Grid<Tile>;
17
18impl Day for Day8 {
19 day_stuff!(8, "14", "34", Grid);
20
21 fn part_1(input: Self::Input) -> Option<String> {
22 let all_antennas = input
23 .iter()
24 .filter_map(|(pos, t)| match *t {
25 Tile::Empty => None,
26 Tile::Antenna(c) => Some((pos, c)),
27 })
28 .collect::<Vec<_>>();
29
30 let mut anti_nodes = HashSet::with_capacity(20);
31
32 for (pos, freq) in all_antennas.iter() {
33 all_antennas
34 .iter()
35 .filter(|(p, f)| p != pos && f == freq)
36 .for_each(|(pos2, _)| {
37 let distance = pos2.sub(pos);
38
39 let anti_one = pos2.add(&distance);
40 let anti_two = pos.sub(&distance);
41
42 if input.in_bounds(&anti_one) {
43 anti_nodes.insert(anti_one);
44 }
45 if input.in_bounds(&anti_two) {
46 anti_nodes.insert(anti_two);
47 }
48 })
49 }
50
51 Some(anti_nodes.len().to_string())
52 }
53
54 fn part_2(input: Self::Input) -> Option<String> {
55 let all_antennas = input
56 .iter()
57 .filter_map(|(pos, t)| match *t {
58 Tile::Empty => None,
59 Tile::Antenna(c) => Some((pos, c)),
60 })
61 .collect::<Vec<_>>();
62
63 let mut anti_nodes = HashSet::with_capacity(20);
64
65 for (pos, freq) in all_antennas.iter() {
66 all_antennas
67 .iter()
68 .filter(|(p, f)| p != pos && f == freq)
69 .for_each(|(pos2, _)| {
70 anti_nodes.insert(*pos);
71
72 let distance = pos2.sub(pos);
73
74 let mut anti_one = pos2.add(&distance);
75 let mut anti_two = pos.sub(&distance);
76
77 while input.in_bounds(&anti_one) {
78 anti_nodes.insert(anti_one);
79 anti_one = anti_one.add(&distance);
80 }
81 while input.in_bounds(&anti_two) {
82 anti_nodes.insert(anti_two);
83 anti_two = anti_two.sub(&distance);
84 }
85 })
86 }
87
88 Some(anti_nodes.len().to_string())
89 }
90
91 fn parse_input(input: &str) -> Self::Input {
92 Grid::parse(input)
93 }
94}