22//! https://adventofcode.com/2024/day/10 
33
44use  std:: { fs,  io} ; 
5+ use  std:: collections:: { BTreeMap ,  BTreeSet } ; 
56use  std:: path:: Path ; 
7+ use  lib:: vector:: Vector ; 
8+ 
9+ type  Vec2  = Vector < i32 ,  2 > ; 
10+ 
11+ const  UP :  Vec2  = Vec2 :: new ( [ 0 ,  -1 ] ) ; 
12+ const  DOWN :  Vec2  = Vec2 :: new ( [ 0 ,  1 ] ) ; 
13+ const  LEFT :  Vec2  = Vec2 :: new ( [ -1 ,  0 ] ) ; 
14+ const  RIGHT :  Vec2  = Vec2 :: new ( [ 1 ,  0 ] ) ; 
615
716fn  main ( )  { 
8-     let  input = Input :: from_file ( format ! ( "{}/input.txt" ,  env!( "CARGO_MANIFEST_DIR" ) ) ) . expect ( "failed to read input" ) ; 
9-     //let input = Input::from_file(format!("{}/example1 .txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input"); 
10-     println ! ( "{input:?}" ) ; 
17+     // let input = Input::from_file(format!("{}/input.txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input");
18+     //let input = Input::from_file(format!("{}/example5 .txt", env!("CARGO_MANIFEST_DIR"))).expect("failed to read input"); 
19+     // println!("{input:?}");
1120
1221    // Part 1 
1322    println ! ( "Part 1: {}" ,  part1( & input) ) ; 
@@ -17,24 +26,107 @@ fn main() {
1726} 
1827
1928fn  part1 ( input :  & Input )  -> usize  { 
20-     0 
29+     let  trailheads:  BTreeSet < Vec2 >  = input. heights . iter ( ) 
30+         . filter_map ( |( & p,  & h) | ( h == 0 ) . then_some ( p) ) . collect ( ) ; 
31+ 
32+     trailheads. into_iter ( ) . map ( |head| score ( head,  & input. heights ) ) . sum ( ) 
33+ } 
34+ 
35+ fn  score ( trailhead :  Vec2 ,  heights :  & BTreeMap < Vec2 ,  u8 > )  -> usize  { 
36+     let  mut  score = 0 ; 
37+ 
38+     let  mut  visited:  BTreeSet < Vec2 >  = [ trailhead] . into_iter ( ) . collect ( ) ; 
39+     let  mut  edge = vec ! [ trailhead] ; 
40+ 
41+     while  let  Some ( pos)  = edge. pop ( )  { 
42+         let  height = heights[ & pos] ; 
43+ 
44+         if  height == 9  { 
45+             score += 1 ; 
46+             continue ; 
47+         } 
48+ 
49+         for  dir in  [ UP ,  DOWN ,  LEFT ,  RIGHT ]  { 
50+             let  next_pos = pos + dir; 
51+             if  visited. contains ( & next_pos)  { 
52+                 continue ; 
53+             } 
54+ 
55+             if  heights. get ( & next_pos) . copied ( )  == Some ( height + 1 )  { 
56+                 visited. insert ( next_pos) ; 
57+                 edge. push ( next_pos) ; 
58+             } 
59+         } 
60+     } 
61+ 
62+     score
2163} 
2264
65+ 
2366fn  part2 ( input :  & Input )  -> usize  { 
24-     0 
67+     let  trailheads:  BTreeSet < Vec2 >  = input. heights . iter ( ) 
68+         . filter_map ( |( & p,  & h) | ( h == 0 ) . then_some ( p) ) . collect ( ) ; 
69+ 
70+     trailheads. into_iter ( ) . map ( |head| rating ( head,  & input. heights ) ) . sum ( ) 
71+ } 
72+ 
73+ fn  rating ( trailhead :  Vec2 ,  heights :  & BTreeMap < Vec2 ,  u8 > )  -> usize  { 
74+     let  mut  rating = 0 ; 
75+ 
76+     let  mut  visited:  BTreeSet < Vec < Vec2 > >  = [ vec ! [ trailhead] ] . into_iter ( ) . collect ( ) ; 
77+     let  mut  edge = vec ! [ vec![ trailhead] ] ; 
78+ 
79+     while  let  Some ( trail)  = edge. pop ( )  { 
80+         let  pos = * trail. last ( ) . unwrap ( ) ; 
81+         let  height = heights[ & pos] ; 
82+         if  height == 9  { 
83+             rating += 1 ; 
84+             continue ; 
85+         } 
86+ 
87+         for  dir in  [ UP ,  DOWN ,  LEFT ,  RIGHT ]  { 
88+             let  next_pos = pos + dir; 
89+             let  new_trail:  Vec < _ >  = trail. iter ( ) . copied ( ) . chain ( [ next_pos] ) . collect ( ) ; 
90+ 
91+             if  visited. contains ( & new_trail)  { 
92+                 continue ; 
93+             } 
94+ 
95+             if  heights. get ( & next_pos) . copied ( )  == Some ( height + 1 )  { 
96+                 visited. insert ( new_trail. clone ( ) ) ; 
97+                 edge. push ( new_trail) ; 
98+             } 
99+         } 
100+     } 
101+ 
102+     rating
25103} 
26104
27105#[ derive( Debug ,  Clone ) ]  
28106struct  Input  { 
29-     values :   Vec < String > , 
107+     heights :   BTreeMap < Vec2 ,   u8 > , 
30108} 
31109
32110impl  Input  { 
33111    fn  from_file ( path :  impl  AsRef < Path > )  -> io:: Result < Self >  { 
34112        let  input = fs:: read_to_string ( path) ?; 
35-         let  values = input. lines ( ) . map ( str:: to_string) . collect ( ) ; 
36113
37-         Ok ( Self  {  values } ) 
114+         let  mut  heights = BTreeMap :: new ( ) ; 
115+ 
116+         for  ( x,  line)  in  input. lines ( ) . enumerate ( )  { 
117+             for  ( y,  c)  in  line. trim ( ) . chars ( ) . enumerate ( )  { 
118+                 if  c == '.'  { 
119+                     continue ; 
120+                 } 
121+ 
122+                 let  pos = Vec2 :: new ( [ x as  i32 ,  y as  i32 ] ) ; 
123+                 let  height = c. to_digit ( 10 ) . unwrap ( )  as  u8 ; 
124+ 
125+                 heights. insert ( pos,  height) ; 
126+             } 
127+         } 
128+ 
129+         Ok ( Self  {  heights } ) 
38130    } 
39131} 
40132
@@ -44,29 +136,29 @@ mod test {
44136
45137    #[ test]  
46138    fn  test_part1 ( )  { 
47-         let  input = Input :: from_file ( "example1 .txt" ) . unwrap ( ) ; 
139+         let  input = Input :: from_file ( "example5 .txt" ) . unwrap ( ) ; 
48140
49-         assert_eq ! ( part1( & input) ,  0 ) ; 
141+         assert_eq ! ( part1( & input) ,  36 ) ; 
50142    } 
51143
52144    #[ test]  
53145    fn  test_part1_solution ( )  { 
54146        let  input = Input :: from_file ( "input.txt" ) . unwrap ( ) ; 
55147
56-         assert_eq ! ( part1( & input) ,  0 ) ; 
148+         assert_eq ! ( part1( & input) ,  776 ) ; 
57149    } 
58150
59151    #[ test]  
60152    fn  test_part2 ( )  { 
61-         let  input = Input :: from_file ( "example1 .txt" ) . unwrap ( ) ; 
153+         let  input = Input :: from_file ( "example5 .txt" ) . unwrap ( ) ; 
62154
63-         assert_eq ! ( part2( & input) ,  0 ) ; 
155+         assert_eq ! ( part2( & input) ,  81 ) ; 
64156    } 
65157
66158    #[ test]  
67159    fn  test_part2_solution ( )  { 
68160        let  input = Input :: from_file ( "input.txt" ) . unwrap ( ) ; 
69161
70-         assert_eq ! ( part2( & input) ,  0 ) ; 
162+         assert_eq ! ( part2( & input) ,  1657 ) ; 
71163    } 
72164} 
0 commit comments