1
1
advent_of_code:: solution!( 12 ) ;
2
2
3
3
use advent_of_code:: maneatingape:: grid:: * ;
4
+ use advent_of_code:: maneatingape:: hash:: * ;
4
5
use advent_of_code:: maneatingape:: point:: * ;
5
6
7
+ struct Garden {
8
+ area : u32 ,
9
+ perimeter : u32 ,
10
+ edges : FastSet < ( Point , Point ) > ,
11
+ }
12
+
6
13
fn parse_data ( input : & str ) -> Grid < u8 > {
7
14
Grid :: parse ( input)
8
15
}
9
16
10
- fn find_data_with_flood ( grid : & Grid < u8 > ) -> Vec < ( usize , usize ) > {
17
+ fn find_gardens ( grid : & Grid < u8 > ) -> Vec < Garden > {
11
18
let mut visited = grid. same_size_with ( false ) ;
12
19
13
- let mut result = vec ! [ ] ;
20
+ let mut gardens = vec ! [ ] ;
14
21
15
22
for y in 0 ..grid. height {
16
23
for x in 0 ..grid. width {
@@ -21,8 +28,11 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
21
28
22
29
let plot = grid[ start_location] ;
23
30
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
+ } ;
26
36
27
37
let mut queue = vec ! [ start_location] ;
28
38
while let Some ( position) = queue. pop ( ) {
@@ -31,52 +41,100 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
31
41
}
32
42
visited[ position] = true ;
33
43
34
- area += 1 ;
35
- perimeter += 4 ;
44
+ garden . area += 1 ;
45
+ garden . perimeter += 4 ;
36
46
37
- for new_position in ORTHOGONAL . map ( |o| position + o) {
47
+ for direction in ORTHOGONAL {
48
+ let new_position = position + direction;
38
49
if grid. contains ( new_position) && grid[ new_position] == plot {
39
50
queue. push ( new_position) ;
40
- perimeter -= 1 ;
51
+ garden. perimeter -= 1 ;
52
+ } else {
53
+ garden. edges . insert ( ( position, direction) ) ;
41
54
}
42
55
}
43
56
}
44
57
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 ;
46
93
}
94
+
95
+ next_edge = next_corner_edge ( & edges) ;
96
+ sides += 1 ;
47
97
}
48
98
49
- result
99
+ sides
50
100
}
51
101
52
102
pub fn part_one ( input : & str ) -> Option < u32 > {
53
103
let grid = parse_data ( input) ;
54
104
55
- let result = find_data_with_flood ( & grid)
105
+ let result = find_gardens ( & grid)
56
106
. into_iter ( )
57
- . map ( |( area , perimeter ) | ( area * perimeter) as u32 )
107
+ . map ( |garden| garden . area * garden . perimeter )
58
108
. sum ( ) ;
59
109
60
110
Some ( result)
61
111
}
62
112
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)
65
122
}
66
123
67
124
#[ cfg( test) ]
68
125
mod tests {
69
126
use super :: * ;
70
-
71
127
#[ test]
72
128
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) ;
74
131
assert_eq ! ( result, Some ( 1930 ) ) ;
75
132
}
76
133
77
134
#[ test]
78
135
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 ) ) ;
81
139
}
82
140
}
0 commit comments