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 {
@@ -24,6 +31,8 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
24
31
let mut area = 0 ;
25
32
let mut perimeter = 0 ;
26
33
34
+ let mut edges = FastSet :: new ( ) ;
35
+
27
36
let mut queue = vec ! [ start_location] ;
28
37
while let Some ( position) = queue. pop ( ) {
29
38
if visited[ position] {
@@ -34,49 +43,101 @@ fn find_data_with_flood(grid: &Grid<u8>) -> Vec<(usize, usize)> {
34
43
area += 1 ;
35
44
perimeter += 4 ;
36
45
37
- for new_position in ORTHOGONAL . map ( |o| position + o) {
46
+ for direction in ORTHOGONAL {
47
+ let new_position = position + direction;
38
48
if grid. contains ( new_position) && grid[ new_position] == plot {
39
49
queue. push ( new_position) ;
40
50
perimeter -= 1 ;
51
+ } else {
52
+ edges. insert ( ( position, direction) ) ;
41
53
}
42
54
}
43
55
}
44
56
45
- result. push ( ( area, perimeter) ) ;
57
+ gardens. push ( Garden {
58
+ area,
59
+ perimeter,
60
+ edges,
61
+ } ) ;
46
62
}
47
63
}
48
64
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
50
103
}
51
104
52
105
pub fn part_one ( input : & str ) -> Option < u32 > {
53
106
let grid = parse_data ( input) ;
54
107
55
- let result = find_data_with_flood ( & grid)
108
+ let result = find_gardens ( & grid)
56
109
. into_iter ( )
57
- . map ( |( area , perimeter ) | ( area * perimeter) as u32 )
110
+ . map ( |garden| garden . area * garden . perimeter )
58
111
. sum ( ) ;
59
112
60
113
Some ( result)
61
114
}
62
115
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)
65
125
}
66
126
67
127
#[ cfg( test) ]
68
128
mod tests {
69
129
use super :: * ;
70
-
71
130
#[ test]
72
131
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) ;
74
134
assert_eq ! ( result, Some ( 1930 ) ) ;
75
135
}
76
136
77
137
#[ test]
78
138
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 ) ) ;
81
142
}
82
143
}
0 commit comments