10
10
#include < set>
11
11
#include < queue>
12
12
13
- struct Data {
13
+ struct Data
14
+ {
14
15
std::vector<std::string> gardens;
15
16
};
16
17
17
- struct Node {
18
- Node* up;
19
- Node* down;
20
- Node* left;
21
- Node* right;
22
- char value;
18
+ bool in_bounds (const Data &data, const Pos &p)
19
+ {
20
+ return p.x >= 0 && p.y >= 0 && p.x < data.gardens [0 ].size () && p.y < data.gardens .size ();
23
21
};
24
22
25
23
int part1 (const Data &data)
26
24
{
27
25
std::set<Pos> unvisited;
28
26
std::map<char , std::vector<std::pair<int , int >>> dimensions;
29
27
30
- for (size_t j = 0 ; j < data.gardens .size (); ++j) {
31
- for (size_t i = 0 ; i < data.gardens [0 ].size (); ++i) {
28
+ for (size_t j = 0 ; j < data.gardens .size (); ++j)
29
+ {
30
+ for (size_t i = 0 ; i < data.gardens [0 ].size (); ++i)
31
+ {
32
32
unvisited.insert ({.x = i, .y = j});
33
33
}
34
34
}
35
35
36
- auto in_bounds = [&](const Pos& p) {
37
- return p.x >= 0 && p.y >= 0 && p.x < data.gardens [0 ].size () && p.y < data.gardens .size ();
38
- };
39
-
40
-
41
- while (unvisited.size () > 0 ) {
36
+ while (unvisited.size () > 0 )
37
+ {
42
38
Pos p = *unvisited.begin ();
43
39
std::queue<Pos> q;
44
40
@@ -48,30 +44,39 @@ int part1(const Data &data)
48
44
q.push (p);
49
45
50
46
// floodfill
51
- while (!q.empty ()) {
47
+ while (!q.empty ())
48
+ {
52
49
Pos cur = q.front ();
53
- if (unvisited.contains (cur)) {
50
+ if (unvisited.contains (cur))
51
+ {
54
52
unvisited.erase (cur);
55
53
++area;
56
- for (auto dir: directions) {
54
+ for (auto dir : directions)
55
+ {
57
56
Pos next = cur + dir;
58
- if (in_bounds (next)) {
57
+ if (in_bounds (data, next))
58
+ {
59
59
char next_char = data.gardens [next.y ][next.x ];
60
- if (next_char == target) {
61
- if (unvisited.contains (next)) {
60
+ if (next_char == target)
61
+ {
62
+ if (unvisited.contains (next))
63
+ {
62
64
q.push (next);
63
65
}
64
66
}
65
- else {
67
+ else
68
+ {
66
69
++perimeter;
67
70
}
68
71
}
69
- else {
72
+ else
73
+ {
70
74
++perimeter;
71
75
}
72
76
}
73
77
}
74
- else {
78
+ else
79
+ {
75
80
// we've been here before
76
81
// but this node was added into the queue by another node
77
82
}
@@ -82,19 +87,119 @@ int part1(const Data &data)
82
87
}
83
88
84
89
int sum = 0 ;
85
- for (auto & [key, val] : dimensions) {
86
- for (auto & [area, perimeter]: val) {
90
+ for (auto &[key, val] : dimensions)
91
+ {
92
+ for (auto &[area, perimeter] : val)
93
+ {
87
94
sum += area * perimeter;
88
- std::cout << std::format (" {}: area {}, perimeter: {}\n " , key, area, perimeter);
89
95
}
90
96
}
91
97
92
98
return sum;
93
99
}
94
100
101
+ int count_corners (const Data &data, Pos cur)
102
+ {
103
+ int cornes = 0 ;
104
+ auto same = [&](Pos next){ return (in_bounds (data, next) && data.gardens [cur.y ][cur.x ] == data.gardens [next.y ][next.x ]);};
105
+
106
+ bool n = same (cur+N);
107
+ bool ne = same (cur+NE);
108
+ bool e = same (cur+E);
109
+ bool se = same (cur+SE);
110
+ bool s = same (cur+S);
111
+ bool sw = same (cur+SW);
112
+ bool w = same (cur+W);
113
+ bool nw = same (cur+NW);
114
+
115
+ // convex corners, or an L shaped region where the current characters
116
+ // AX XA A A
117
+ // A A AX AX
118
+ // concave corners, or when a cell is the same as its two orthongal neighbors but not the same
119
+ // as its diagonal neighboer
120
+ // AA AA AX XA
121
+ // XA XA AA AA
122
+
123
+ // the left side of the || operator checks convex corners
124
+ // the right side of the || operators chekcs concave corners
125
+ if (!n && !e || n && e && !ne) cornes += 1 ;
126
+ if (!e && !s || e && s && !se) cornes += 1 ;
127
+ if (!s && !w || s && w && !sw) cornes += 1 ;
128
+ if (!w && !n || w && n && !nw) cornes += 1 ;
129
+
130
+ return cornes;
131
+ }
132
+
95
133
int part2 (const Data &data)
96
134
{
97
- return 0 ;
135
+ std::set<Pos> unvisited;
136
+ std::map<char , std::vector<std::pair<int , int >>> dimensions;
137
+
138
+ for (size_t j = 0 ; j < data.gardens .size (); ++j)
139
+ {
140
+ for (size_t i = 0 ; i < data.gardens [0 ].size (); ++i)
141
+ {
142
+ unvisited.insert ({.x = i, .y = j});
143
+ }
144
+ }
145
+
146
+ while (unvisited.size () > 0 )
147
+ {
148
+ Pos p = *unvisited.begin ();
149
+ std::queue<Pos> q;
150
+
151
+ char target = data.gardens [p.y ][p.x ];
152
+ int area = 0 ;
153
+ int sides = 0 ;
154
+ q.push (p);
155
+
156
+ // floodfill
157
+ while (!q.empty ())
158
+ {
159
+ Pos cur = q.front ();
160
+ if (unvisited.contains (cur))
161
+ {
162
+ unvisited.erase (cur);
163
+ ++area;
164
+ sides += count_corners (data, cur);
165
+ for (auto dir : directions)
166
+ {
167
+ Pos next = cur + dir;
168
+ if (in_bounds (data, next))
169
+ {
170
+ char next_char = data.gardens [next.y ][next.x ];
171
+ if (next_char == target)
172
+ {
173
+ if (unvisited.contains (next))
174
+ {
175
+ q.push (next);
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ else
182
+ {
183
+ // we've been here before
184
+ // but this node was added into the queue by another node
185
+ }
186
+ q.pop ();
187
+ }
188
+
189
+ dimensions[target].push_back ({area, sides});
190
+ }
191
+
192
+ int sum = 0 ;
193
+ for (auto &[key, val] : dimensions)
194
+ {
195
+ for (auto &[area, sides] : val)
196
+ {
197
+ sum += area * sides;
198
+ std::cout << std::format (" {}: area {}, sides: {}\n " , key, area, sides);
199
+ }
200
+ }
201
+
202
+ return sum;
98
203
}
99
204
100
205
Data parse ()
@@ -155,15 +260,17 @@ int main(int argc, char **argv)
155
260
156
261
auto first = part1 (data);
157
262
std::cout << " Part 1: " << first << std::endl;
158
-
263
+
159
264
auto second = part2 (data);
160
265
std::cout << " Part 2: " << second << std::endl;
161
266
162
267
first != answer1 ? throw std::runtime_error (" Part 1 incorrect" ) : nullptr ;
163
268
second != answer2 ? throw std::runtime_error (" Part 2 incorrect" ) : nullptr ;
164
269
165
- for (int i = 1 ; i < argc; ++i) {
166
- if (std::string (argv[i]) == " --benchmark" ) {
270
+ for (int i = 1 ; i < argc; ++i)
271
+ {
272
+ if (std::string (argv[i]) == " --benchmark" )
273
+ {
167
274
benchmark::Initialize (&argc, argv);
168
275
benchmark::RunSpecifiedBenchmarks ();
169
276
return 0 ;
0 commit comments