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 {
@@ -23,6 +30,7 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
23
30
24
31
let mut area = 0 ;
25
32
let mut perimeter = 0 ;
33
+ let mut edges = FastSet :: new ( ) ;
26
34
27
35
let mut queue = vec ! [ start_location] ;
28
36
while let Some ( position) = queue. pop ( ) {
@@ -34,49 +42,101 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
34
42
area += 1 ;
35
43
perimeter += 4 ;
36
44
37
- for new_position in ORTHOGONAL . map ( |o| position + o) {
45
+ for direction in ORTHOGONAL {
46
+ let new_position = position + direction;
38
47
if grid. contains ( new_position) && grid[ new_position] == plot {
39
48
queue. push ( new_position) ;
40
49
perimeter -= 1 ;
50
+ } else {
51
+ edges. insert ( ( position, direction) ) ;
41
52
}
42
53
}
43
54
}
44
55
45
- result. push ( ( area, perimeter) ) ;
56
+ gardens. push ( Garden {
57
+ area,
58
+ perimeter,
59
+ edges,
60
+ } ) ;
61
+ }
62
+ }
63
+
64
+ gardens
65
+ }
66
+
67
+ fn find_sides ( mut edges : FastSet < ( Point , Point ) > ) -> u32 {
68
+ let next_corner_edge = |edges : & FastSet < ( Point , Point ) > | {
69
+ let mut edge = edges. iter ( ) . next ( ) . copied ( ) ?;
70
+ loop {
71
+ let new_edge = ( edge. 0 + edge. 1 . clockwise ( ) , edge. 1 ) ;
72
+ if !edges. contains ( & new_edge) {
73
+ return Some ( edge) ;
74
+ }
75
+
76
+ edge = new_edge;
77
+ }
78
+ } ;
79
+
80
+ let mut sides = 0 ;
81
+ let mut next_edge = next_corner_edge ( & edges) ;
82
+ while let Some ( edge @ ( p, d) ) = next_edge {
83
+ edges. remove ( & edge) ;
84
+
85
+ let left_edge = ( p + d. counter_clockwise ( ) , d) ;
86
+ if edges. contains ( & left_edge) {
87
+ next_edge = Some ( left_edge) ;
88
+ continue ;
89
+ }
90
+
91
+ let right_edge = ( p + d. clockwise ( ) , d) ;
92
+ if edges. contains ( & right_edge) {
93
+ next_edge = Some ( right_edge) ;
94
+ continue ;
46
95
}
96
+
97
+ next_edge = next_corner_edge ( & edges) ;
98
+ sides += 1 ;
47
99
}
48
100
49
- result
101
+ sides
50
102
}
51
103
52
104
pub fn part_one ( input : & str ) -> Option < u32 > {
53
105
let grid = parse_data ( input) ;
54
106
55
- let result = find_data_with_flood ( & grid)
107
+ let result = find_gardens ( & grid)
56
108
. into_iter ( )
57
- . map ( |( area , perimeter ) | ( area * perimeter) as u32 )
109
+ . map ( |garden| garden . area * garden . perimeter )
58
110
. sum ( ) ;
59
111
60
112
Some ( result)
61
113
}
62
114
63
- pub fn part_two ( _input : & str ) -> Option < u32 > {
64
- None
115
+ pub fn part_two ( input : & str ) -> Option < u32 > {
116
+ let grid = parse_data ( input) ;
117
+
118
+ let result = find_gardens ( & grid)
119
+ . into_iter ( )
120
+ . map ( |garden| garden. area * find_sides ( garden. edges ) )
121
+ . sum ( ) ;
122
+
123
+ Some ( result)
65
124
}
66
125
67
126
#[ cfg( test) ]
68
127
mod tests {
69
128
use super :: * ;
70
-
71
129
#[ test]
72
130
fn test_part_one ( ) {
73
- let result = part_one ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
131
+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
132
+ let result = part_one ( & input) ;
74
133
assert_eq ! ( result, Some ( 1930 ) ) ;
75
134
}
76
135
77
136
#[ test]
78
137
fn test_part_two ( ) {
79
- let result = part_two ( & advent_of_code:: template:: read_file ( "examples" , DAY ) ) ;
80
- assert_eq ! ( result, None ) ;
138
+ let input = advent_of_code:: template:: read_file ( "examples" , DAY ) ;
139
+ let result = part_two ( & input) ;
140
+ assert_eq ! ( result, Some ( 1206 ) ) ;
81
141
}
82
142
}
0 commit comments