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 {
@@ -24,6 +31,8 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
2431 let mut area = 0 ;
2532 let mut perimeter = 0 ;
2633
34+ let mut edges = FastSet :: new ( ) ;
35+
2736 let mut queue = vec ! [ start_location] ;
2837 while let Some ( position) = queue. pop ( ) {
2938 if visited[ position] {
@@ -34,49 +43,101 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
3443 area += 1 ;
3544 perimeter += 4 ;
3645
37- for new_position in ORTHOGONAL . map ( |o| position + o) {
46+ for direction in ORTHOGONAL {
47+ let new_position = position + direction;
3848 if grid. contains ( new_position) && grid[ new_position] == plot {
3949 queue. push ( new_position) ;
4050 perimeter -= 1 ;
51+ } else {
52+ edges. insert ( ( position, direction) ) ;
4153 }
4254 }
4355 }
4456
45- result. push ( ( area, perimeter) ) ;
57+ gardens. push ( Garden {
58+ area,
59+ perimeter,
60+ edges,
61+ } ) ;
4662 }
4763 }
4864
49- result
65+ gardens
66+ }
67+
68+ fn find_sides ( mut edges : FastSet < ( Point , Point ) > ) -> u32 {
69+ let next_corner_edge = |edges : & FastSet < ( Point , Point ) > | {
70+ let mut edge = edges. iter ( ) . next ( ) . copied ( ) ?;
71+ loop {
72+ let new_edge = ( edge. 0 + edge. 1 . clockwise ( ) , edge. 1 ) ;
73+ if !edges. contains ( & new_edge) {
74+ return Some ( edge) ;
75+ }
76+
77+ edge = new_edge;
78+ }
79+ } ;
80+
81+ let mut sides = 0 ;
82+ let mut next_edge = next_corner_edge ( & edges) ;
83+ while let Some ( edge @ ( p, d) ) = next_edge {
84+ edges. remove ( & edge) ;
85+
86+ let left_edge = ( p + d. counter_clockwise ( ) , d) ;
87+ if edges. contains ( & left_edge) {
88+ next_edge = Some ( left_edge) ;
89+ continue ;
90+ }
91+
92+ let right_edge = ( p + d. clockwise ( ) , d) ;
93+ if edges. contains ( & right_edge) {
94+ next_edge = Some ( right_edge) ;
95+ continue ;
96+ }
97+
98+ next_edge = next_corner_edge ( & edges) ;
99+ sides += 1 ;
100+ }
101+
102+ sides
50103}
51104
52105pub fn part_one ( input : & str ) -> Option < u32 > {
53106 let grid = parse_data ( input) ;
54107
55- let result = find_data_with_flood ( & grid)
108+ let result = find_gardens ( & grid)
56109 . into_iter ( )
57- . map ( |( area , perimeter ) | ( area * perimeter) as u32 )
110+ . map ( |garden| garden . area * garden . perimeter )
58111 . sum ( ) ;
59112
60113 Some ( result)
61114}
62115
63- pub fn part_two ( _input : & str ) -> Option < u32 > {
64- None
116+ pub fn part_two ( input : & str ) -> Option < u32 > {
117+ let grid = parse_data ( input) ;
118+
119+ let result = find_gardens ( & grid)
120+ . into_iter ( )
121+ . map ( |garden| garden. area * find_sides ( garden. edges ) )
122+ . sum ( ) ;
123+
124+ Some ( result)
65125}
66126
67127#[ cfg( test) ]
68128mod tests {
69129 use super :: * ;
70-
71130 #[ test]
72131 fn test_part_one ( ) {
73- let result = part_one ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
132+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
133+ let result = part_one ( & input) ;
74134 assert_eq ! ( result, Some ( 1930 ) ) ;
75135 }
76136
77137 #[ test]
78138 fn test_part_two ( ) {
79- let result = part_two ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
80- assert_eq ! ( result, None ) ;
139+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
140+ let result = part_two ( & input) ;
141+ assert_eq ! ( result, Some ( 1206 ) ) ;
81142 }
82143}
0 commit comments