-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday08.rs
86 lines (70 loc) · 2.35 KB
/
day08.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use itertools::Itertools;
use std::collections::HashSet;
use crate::utils::v2::{
coords::Coordinates,
grid::{DenseGrid, Grid, GridFind},
solver,
};
#[derive(Clone, Copy)]
enum AntinodeSpan {
Limited,
Unlimited,
}
pub struct Solver;
impl Solver {
fn compute_antinodes(
&self,
grid: &DenseGrid<char, i32>,
a: Coordinates<i32>,
b: Coordinates<i32>,
antinode_span: AntinodeSpan,
) -> Vec<Coordinates<i32>> {
let delta = a - b;
let da = if a + delta == b { -delta } else { delta };
let db = if b + delta == a { -delta } else { delta };
let range = match antinode_span {
AntinodeSpan::Limited => 1..2,
AntinodeSpan::Unlimited => 1..i32::MAX,
};
let antinodes_a = range
.clone()
.map(move |i| a + da * i)
.take_while(|&coords| grid.is_coords_in_bounds(coords))
.collect_vec();
let antinodes_b = range
.map(move |i| b + db * i)
.take_while(|&coords| grid.is_coords_in_bounds(coords))
.collect_vec();
let mut antinodes = match antinode_span {
AntinodeSpan::Limited => vec![],
AntinodeSpan::Unlimited => vec![a, b],
};
antinodes.extend(antinodes_a);
antinodes.extend(antinodes_b);
antinodes
}
fn solve(&self, input: &str, antinode_span: AntinodeSpan) -> usize {
let chars = input.chars().filter(|c| c.is_alphanumeric()).unique();
let grid = DenseGrid::<char, i32>::try_from(input).unwrap();
let mut all_antinodes = HashSet::new();
for c in chars {
let nodes = grid.find_all(&c).into_iter().map(Coordinates::from);
let antinodes = nodes
.tuple_combinations()
.flat_map(|(a, b)| self.compute_antinodes(&grid, a, b, antinode_span))
.filter(|&coords| grid.is_coords_in_bounds(coords));
all_antinodes.extend(antinodes);
}
all_antinodes.len()
}
}
impl solver::Solver<2024, 8> for Solver {
type Part1 = usize;
type Part2 = usize;
fn solve_part_one(&self, input: &str) -> Self::Part1 {
self.solve(input, AntinodeSpan::Limited)
}
fn solve_part_two(&self, input: &str) -> Self::Part2 {
self.solve(input, AntinodeSpan::Unlimited)
}
}