11advent_of_code:: solution!( 2 ) ;
22use advent_of_code:: * ;
33use std:: cmp:: Ordering ;
4-
5- #[ derive( Debug , PartialEq , Eq ) ]
6- enum Trend {
7- Unknown ,
8- Increasing ,
9- Decreasing ,
10- }
4+ use std:: iter:: once;
115
126enum Diff {
7+ Safe ( Trend ) ,
138 Unsafe ,
14- SafeIncrease ,
15- SafeDecrease ,
169}
1710
18- fn diff ( part : u32 , prev_part : u32 ) -> Diff {
19- match ( part. cmp ( & prev_part) , part. abs_diff ( prev_part) ) {
20- ( Ordering :: Greater , diff) if diff <= 3 => Diff :: SafeIncrease ,
21- ( Ordering :: Less , diff) if diff <= 3 => Diff :: SafeDecrease ,
22- ( _, _) => Diff :: Unsafe ,
23- }
11+ #[ derive( PartialEq , Eq ) ]
12+ enum Trend {
13+ Upward ,
14+ Downward ,
2415}
2516
2617pub fn part_one ( input : & str ) -> Option < u32 > {
2718 let mut safe_count = 0 ;
2819 for line in input. lines ( ) {
2920 let mut safe = 1 ;
3021 let mut prev_part: Option < u32 > = None ;
31- let mut prev_trend = Trend :: Unknown ;
22+ let mut trend : Option < Trend > = None ;
3223 ' parts: for part in parse_u32_parts ( line) {
3324 if let Some ( prev_part) = prev_part {
34- match ( diff ( part, prev_part) , prev_trend) {
35- ( Diff :: SafeIncrease , Trend :: Increasing | Trend :: Unknown ) => {
36- prev_trend = Trend :: Increasing ;
37- }
38- ( Diff :: SafeDecrease , Trend :: Decreasing | Trend :: Unknown ) => {
39- prev_trend = Trend :: Decreasing ;
40- }
25+ match ( diff ( part, prev_part) , & trend) {
26+ ( Diff :: Safe ( diff_trend) , Some ( curr_trend) ) if diff_trend == * curr_trend => ( ) ,
27+ ( Diff :: Safe ( diff_trend) , None ) => trend = Some ( diff_trend) ,
4128 ( _, _) => {
4229 safe = 0 ;
4330 break ' parts;
@@ -51,8 +38,54 @@ pub fn part_one(input: &str) -> Option<u32> {
5138 Some ( safe_count)
5239}
5340
54- pub fn part_two ( _input : & str ) -> Option < u32 > {
55- None
41+ pub fn part_two ( input : & str ) -> Option < u32 > {
42+ let mut safe_count = 0 ;
43+ for line in input. lines ( ) {
44+ let parts = parse_u32_parts ( line) . collect :: < Vec < u32 > > ( ) ;
45+ if is_safe_with_dampener ( parts) {
46+ safe_count += 1 ;
47+ }
48+ }
49+ Some ( safe_count)
50+ }
51+
52+ // Brute-force baby! 🤠💨🔫
53+ fn is_safe_with_dampener ( parts : Vec < u32 > ) -> bool {
54+ for sans_index in once ( None ) . chain ( ( 0 ..parts. len ( ) ) . map ( Some ) ) {
55+ if is_safe ( parts. clone ( ) , sans_index) {
56+ return true ;
57+ }
58+ }
59+ false
60+ }
61+
62+ fn is_safe ( mut parts : Vec < u32 > , remove_index : Option < usize > ) -> bool {
63+ if let Some ( i) = remove_index {
64+ parts. remove ( i) ;
65+ } ;
66+
67+ let mut prev_part: Option < u32 > = None ;
68+ let mut trend = None ;
69+ for i in 0 ..parts. len ( ) {
70+ let current_part_u32 = parts[ i] ;
71+ if let Some ( prev_part_u32) = prev_part {
72+ match ( diff ( current_part_u32, prev_part_u32) , & trend) {
73+ ( Diff :: Safe ( diff_trend) , Some ( curr_trend) ) if diff_trend == * curr_trend => ( ) ,
74+ ( Diff :: Safe ( diff_trend) , None ) => trend = Some ( diff_trend) ,
75+ ( _, _) => return false ,
76+ }
77+ }
78+ prev_part = Some ( current_part_u32) ;
79+ }
80+ true
81+ }
82+
83+ fn diff ( part : u32 , prev_part : u32 ) -> Diff {
84+ match ( part. cmp ( & prev_part) , part. abs_diff ( prev_part) ) {
85+ ( Ordering :: Greater , 1 ..=3 ) => Diff :: Safe ( Trend :: Upward ) ,
86+ ( Ordering :: Less , 1 ..=3 ) => Diff :: Safe ( Trend :: Downward ) ,
87+ _ => Diff :: Unsafe ,
88+ }
5689}
5790
5891#[ cfg( test) ]
@@ -68,6 +101,6 @@ mod tests {
68101 #[ test]
69102 fn test_part_two ( ) {
70103 let result = part_two ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
71- assert_eq ! ( result, None ) ;
104+ assert_eq ! ( result, Some ( 4 ) ) ;
72105 }
73106}
0 commit comments