-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday10.rs
118 lines (100 loc) · 3.03 KB
/
day10.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#[derive(Copy, Clone)]
struct Trailhead {
destinations: [u16; 40],
len: u8,
}
impl Trailhead {
fn new() -> Self {
Self {
destinations: [0; 40],
len: 0,
}
}
fn push(&mut self, n: u16) {
self.destinations[self.len as usize] = n;
self.len += 1;
}
fn len(&self) -> usize {
self.len as usize
}
fn unique(&self) -> usize {
self.destinations
.iter()
.take(self.len())
.sorted_unstable()
.dedup()
.count()
}
}
#[derive(Clone)]
struct Solution {
trailheads: Vec<Trailhead>,
}
impl Solver for Solution {
fn new(input: &str) -> Anyhow<Self> {
let line_len = input.bytes().take_while_inclusive(|&b| b != b'\n').count();
let mut trailheads = Vec::with_capacity(400);
let mut queue = Vec::new();
// perform DFS from every '0' node, ie. each trailhead
for i in input.bytes().positions(|b| b == b'0') {
let mut last = i;
let mut trailhead = Trailhead::new();
queue.push((i, b'0'));
while let Some((i, b)) = queue.pop() {
macro_rules! check_neighbour {
($n:expr) => {
// only continue if not backtracking and next is 1 bigger than current
if $n != last && $n < input.len() && input.as_bytes()[$n] == b + 1 {
// if current is '8', then next must be '9' and therefore a destination of the trailhead
if b == b'8' {
trailhead.push($n as u16);
} else {
queue.push(($n, input.as_bytes()[$n]));
}
}
};
}
check_neighbour!(i - 1); // look left
check_neighbour!(i + 1); // look right
check_neighbour!(i - line_len); // look up
check_neighbour!(i + line_len); // look down
last = i;
}
trailheads.push(trailhead);
queue.clear();
}
Ok(Self { trailheads })
}
fn part1(&mut self) -> Anyhow<impl fmt::Display> {
Ok(self.trailheads.iter().fold(0, |acc, th| acc + th.unique()))
}
fn part2(&mut self) -> Anyhow<impl fmt::Display> {
Ok(self.trailheads.iter().fold(0, |acc, th| acc + th.len()))
}
}
aoc::solution!();
#[cfg(test)]
mod test {
use super::{Solution, Solver};
const INPUT: &str = r"89010123
78121874
87430965
96549874
45678903
32019012
01329801
10456732
";
#[test]
fn test_part1() {
let mut solution = Solution::new(INPUT).unwrap();
let answer = solution.part1().unwrap().to_string();
assert_eq!(answer, "36");
}
#[test]
fn test_part2() {
let mut solution = Solution::new(INPUT).unwrap();
let answer = solution.part2().unwrap().to_string();
assert_eq!(answer, "81");
}
}