11advent_of_code:: solution!( 12 ) ;
22
33use advent_of_code:: maneatingape:: grid:: * ;
4+ use advent_of_code:: maneatingape:: hash:: * ;
45use advent_of_code:: maneatingape:: point:: * ;
56
7+ struct Garden {
8+ area : u32 ,
9+ perimeter : u32 ,
10+ edges : FastSet < ( Point , Point ) > ,
11+ }
12+
613fn parse_data ( input : & str ) -> Grid < u8 > {
714 Grid :: parse ( input)
815}
916
10- fn find_data_with_flood ( grid : & Grid < u8 > ) -> Vec < ( usize , usize ) > {
17+ fn find_gardens ( grid : & Grid < u8 > ) -> Vec < Garden > {
1118 let mut visited = grid. same_size_with ( false ) ;
1219
13- let mut result = vec ! [ ] ;
20+ let mut gardens = vec ! [ ] ;
1421
1522 for y in 0 ..grid. height {
1623 for x in 0 ..grid. width {
@@ -21,8 +28,11 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
2128
2229 let plot = grid[ start_location] ;
2330
24- let mut area = 0 ;
25- let mut perimeter = 0 ;
31+ let mut garden = Garden {
32+ area : 0 ,
33+ perimeter : 0 ,
34+ edges : FastSet :: new ( ) ,
35+ } ;
2636
2737 let mut queue = vec ! [ start_location] ;
2838 while let Some ( position) = queue. pop ( ) {
@@ -31,52 +41,100 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
3141 }
3242 visited[ position] = true ;
3343
34- area += 1 ;
35- perimeter += 4 ;
44+ garden . area += 1 ;
45+ garden . perimeter += 4 ;
3646
37- for new_position in ORTHOGONAL . map ( |o| position + o) {
47+ for direction in ORTHOGONAL {
48+ let new_position = position + direction;
3849 if grid. contains ( new_position) && grid[ new_position] == plot {
3950 queue. push ( new_position) ;
40- perimeter -= 1 ;
51+ garden. perimeter -= 1 ;
52+ } else {
53+ garden. edges . insert ( ( position, direction) ) ;
4154 }
4255 }
4356 }
4457
45- result. push ( ( area, perimeter) ) ;
58+ gardens. push ( garden) ;
59+ }
60+ }
61+
62+ gardens
63+ }
64+
65+ fn find_sides ( mut edges : FastSet < ( Point , Point ) > ) -> u32 {
66+ let next_corner_edge = |edges : & FastSet < ( Point , Point ) > | {
67+ let mut edge = edges. iter ( ) . next ( ) . copied ( ) ?;
68+ loop {
69+ let new_edge = ( edge. 0 + edge. 1 . clockwise ( ) , edge. 1 ) ;
70+ if !edges. contains ( & new_edge) {
71+ return Some ( edge) ;
72+ }
73+
74+ edge = new_edge;
75+ }
76+ } ;
77+
78+ let mut sides = 0 ;
79+ let mut next_edge = next_corner_edge ( & edges) ;
80+ while let Some ( edge @ ( p, d) ) = next_edge {
81+ edges. remove ( & edge) ;
82+
83+ let left_edge = ( p + d. counter_clockwise ( ) , d) ;
84+ if edges. contains ( & left_edge) {
85+ next_edge = Some ( left_edge) ;
86+ continue ;
87+ }
88+
89+ let right_edge = ( p + d. clockwise ( ) , d) ;
90+ if edges. contains ( & right_edge) {
91+ next_edge = Some ( right_edge) ;
92+ continue ;
4693 }
94+
95+ next_edge = next_corner_edge ( & edges) ;
96+ sides += 1 ;
4797 }
4898
49- result
99+ sides
50100}
51101
52102pub fn part_one ( input : & str ) -> Option < u32 > {
53103 let grid = parse_data ( input) ;
54104
55- let result = find_data_with_flood ( & grid)
105+ let result = find_gardens ( & grid)
56106 . into_iter ( )
57- . map ( |( area , perimeter ) | ( area * perimeter) as u32 )
107+ . map ( |garden| garden . area * garden . perimeter )
58108 . sum ( ) ;
59109
60110 Some ( result)
61111}
62112
63- pub fn part_two ( _input : & str ) -> Option < u32 > {
64- None
113+ pub fn part_two ( input : & str ) -> Option < u32 > {
114+ let grid = parse_data ( input) ;
115+
116+ let result = find_gardens ( & grid)
117+ . into_iter ( )
118+ . map ( |garden| garden. area * find_sides ( garden. edges ) )
119+ . sum ( ) ;
120+
121+ Some ( result)
65122}
66123
67124#[ cfg( test) ]
68125mod tests {
69126 use super :: * ;
70-
71127 #[ test]
72128 fn test_part_one ( ) {
73- let result = part_one ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
129+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
130+ let result = part_one ( & input) ;
74131 assert_eq ! ( result, Some ( 1930 ) ) ;
75132 }
76133
77134 #[ test]
78135 fn test_part_two ( ) {
79- let result = part_two ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
80- assert_eq ! ( result, None ) ;
136+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
137+ let result = part_two ( & input) ;
138+ assert_eq ! ( result, Some ( 1206 ) ) ;
81139 }
82140}
0 commit comments