generated from fspoettel/advent-of-code-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path02.rs
106 lines (95 loc) · 2.85 KB
/
02.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
advent_of_code::solution!(2);
use advent_of_code::*;
use std::cmp::Ordering;
use std::iter::once;
enum Diff {
Safe(Trend),
Unsafe,
}
#[derive(PartialEq, Eq)]
enum Trend {
Upward,
Downward,
}
pub fn part_one(input: &str) -> Option<u32> {
let mut safe_count = 0;
for line in input.lines() {
let mut safe = 1;
let mut prev_part: Option<u32> = None;
let mut trend: Option<Trend> = None;
'parts: for part in line_into_u32_iter(line) {
if let Some(prev_part) = prev_part {
match (diff(part, prev_part), &trend) {
(Diff::Safe(diff_trend), Some(curr_trend)) if diff_trend == *curr_trend => (),
(Diff::Safe(diff_trend), None) => trend = Some(diff_trend),
(_, _) => {
safe = 0;
break 'parts;
}
};
}
prev_part = Some(part);
}
safe_count += safe;
}
Some(safe_count)
}
pub fn part_two(input: &str) -> Option<u32> {
let mut safe_count = 0;
for line in input.lines() {
let parts = line_into_u32_iter(line).collect::<Vec<u32>>();
if is_safe_with_dampener(parts) {
safe_count += 1;
}
}
Some(safe_count)
}
// Brute-force baby! 🤠💨🔫
fn is_safe_with_dampener(parts: Vec<u32>) -> bool {
for sans_index in once(None).chain((0..parts.len()).map(Some)) {
if is_safe(parts.clone(), sans_index) {
return true;
}
}
false
}
fn is_safe(mut parts: Vec<u32>, remove_index: Option<usize>) -> bool {
if let Some(i) = remove_index {
parts.remove(i);
};
let mut prev_part: Option<u32> = None;
let mut trend = None;
for i in 0..parts.len() {
let current_part_u32 = parts[i];
if let Some(prev_part_u32) = prev_part {
match (diff(current_part_u32, prev_part_u32), &trend) {
(Diff::Safe(diff_trend), Some(curr_trend)) if diff_trend == *curr_trend => (),
(Diff::Safe(diff_trend), None) => trend = Some(diff_trend),
(_, _) => return false,
}
}
prev_part = Some(current_part_u32);
}
true
}
fn diff(part: u32, prev_part: u32) -> Diff {
match (part.cmp(&prev_part), part.abs_diff(prev_part)) {
(Ordering::Greater, 1..=3) => Diff::Safe(Trend::Upward),
(Ordering::Less, 1..=3) => Diff::Safe(Trend::Downward),
_ => Diff::Unsafe,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(2));
}
#[test]
fn test_part_two() {
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
assert_eq!(result, Some(4));
}
}