1
+ #include " common_headers.hpp"
2
+ #include < array>
3
+ #include < set>
4
+ #include < stack>
5
+
6
+ constexpr std::array<int ,5 > offsets{0 , 1 , 0 , -1 , 0 };
7
+
8
+ using CoordinateMap = std::set<std::pair<int , int >>;
9
+
10
+ [[nodiscard]] size_t calculatePerimeter (const std::vector<std::string>& map, int row, int col) {
11
+ size_t perimeter{};
12
+ for (int i = 0 ; i < 4 ; ++i) {
13
+ const int newRow{row + offsets[i]};
14
+ const int newCol{col + offsets[i + 1 ]};
15
+ if (newRow < 0 || newCol < 0 || newRow >= map.size () || newCol >= map[0 ].size ()) {
16
+ ++perimeter;
17
+ }
18
+ else {
19
+ perimeter += map[row][col] != map[newRow][newCol];
20
+ }
21
+ }
22
+ return perimeter;
23
+ }
24
+
25
+ [[nodiscard]] size_t calculateCorner (const std::vector<std::string>& map, int row, int col) {
26
+ size_t counter{};
27
+ const char plot{map[row][col]};
28
+ // top left outer
29
+ if ((row - 1 < 0 || plot != map[row - 1 ][col]) && (col - 1 < 0 || map[row][col - 1 ] != plot)) {
30
+ ++counter;
31
+ }
32
+ // top right outer
33
+ if ((row - 1 < 0 || plot != map[row - 1 ][col]) && (col + 1 >= map[0 ].size () || map[row][col + 1 ] != plot)) {
34
+ ++counter;
35
+ }
36
+ // bottom left
37
+ if ((row + 1 >= map.size () || map[row + 1 ][col] != plot) && (col - 1 < 0 || map[row][col - 1 ] != plot)) {
38
+ ++counter;
39
+ }
40
+ // bottom right
41
+ if ((row + 1 >= map.size () || map[row + 1 ][col] != plot) && (col + 1 >= map[0 ].size () || map[row][col + 1 ] != plot)) {
42
+ ++counter;
43
+ }
44
+
45
+ // top left inner
46
+ if (row - 1 >= 0 && map[row - 1 ][col] == plot && col - 1 >= 0 && map[row][col - 1 ] == plot && map[row - 1 ][col - 1 ] != plot) {
47
+ ++counter;
48
+ }
49
+
50
+ // top right inner
51
+ if (row - 1 >= 0 && map[row - 1 ][col] == plot && col + 1 < map[0 ].size () && map[row][col + 1 ] == plot && map[row - 1 ][col + 1 ] != plot) {
52
+ ++counter;
53
+ }
54
+
55
+ // bottom left inner
56
+ if (row + 1 < map.size () && map[row + 1 ][col] == plot && col - 1 >= 0 && map[row][col - 1 ] == plot && map[row + 1 ][col - 1 ] != plot) {
57
+ ++counter;
58
+ }
59
+ // bottom right inner
60
+ if (row + 1 < map.size () && map[row + 1 ][col] == plot && col + 1 < map[0 ].size () && map[row][col + 1 ] == plot && map[row + 1 ][col + 1 ] != plot) {
61
+ ++counter;
62
+ }
63
+
64
+ return counter;
65
+ }
66
+
67
+
68
+ template <typename Handler>
69
+ void traverse (const std::vector<std::string>& map, int row, int col, CoordinateMap& visited, Handler& handler) {
70
+
71
+ const char plot{map[row][col]};
72
+
73
+ std::stack<std::pair<int , int >> dfs;
74
+ dfs.emplace (row, col);
75
+
76
+ while (!dfs.empty ()) {
77
+ const auto [r, c] = dfs.top ();
78
+ dfs.pop ();
79
+ if (visited.emplace (std::pair{r, c}).second == false ) continue ;
80
+
81
+ handler (map, r, c);
82
+
83
+ for (int i = 0 ; i < 4 ; ++i) {
84
+ const int newRow{r + offsets[i]};
85
+ const int newCol{c + offsets[i + 1 ]};
86
+ if (newRow < 0 || newCol < 0 || newRow >= map.size () || newCol >= map[0 ].size ()) {
87
+ continue ;
88
+ }
89
+ else if (plot == map[newRow][newCol]) {
90
+ dfs.emplace (newRow, newCol);
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ [[nodiscard]] size_t solveFirstPart (const std::vector<std::string>& map) {
97
+ size_t totalPrice{};
98
+ CoordinateMap visited;
99
+
100
+
101
+ for (int row = 0 ; row < map.size (); ++row) {
102
+ for (int col = 0 ; col < map[0 ].size (); ++col) {
103
+ if (visited.count (std::pair (row, col))) continue ;
104
+
105
+ size_t area{};
106
+ size_t perimeter{};
107
+ auto calculator = [&](const std::vector<std::string>& map, int row, int col) mutable {
108
+ ++area;
109
+ perimeter += calculatePerimeter (map, row, col);
110
+ };
111
+
112
+ traverse (map, row, col, visited, calculator);
113
+ totalPrice += area * perimeter;
114
+ }
115
+ }
116
+ return totalPrice;
117
+ }
118
+
119
+ [[nodiscard]] size_t solveSecondPart (const std::vector<std::string>& map) {
120
+ size_t totalPrice{};
121
+ CoordinateMap visited;
122
+
123
+ for (int row = 0 ; row < map.size (); ++row) {
124
+ for (int col = 0 ; col < map[0 ].size (); ++col) {
125
+ if (visited.count (std::pair (row, col))) continue ;
126
+
127
+ size_t area{};
128
+ size_t perimeter{};
129
+ auto calculator = [&](const std::vector<std::string>& map, int row, int col) mutable {
130
+ ++area;
131
+ perimeter += calculateCorner (map, row, col);
132
+ };
133
+ traverse (map, row, col, visited, calculator);
134
+ totalPrice += area * perimeter;
135
+ }
136
+ }
137
+
138
+ return totalPrice;
139
+ }
140
+
141
+
142
+ void printHelp ()
143
+ {
144
+ std::cerr << " \n Usage:\n "
145
+ << " The program requires 2 args: (part1, part2) and the path to the file."
146
+ << " \n For example, ./day7 part1 data/day7.txt" ;
147
+ }
148
+
149
+ int main (int argc, char * argv[])
150
+ {
151
+ if (argc != 3 ) {
152
+ printHelp ();
153
+ return 1 ;
154
+ }
155
+
156
+ std::string_view task{argv[1 ]};
157
+ if (task != " part1" && task != " part2" ) {
158
+ std::cerr << " \n first arg can be either `part1` or `part2`\n " ;
159
+ printHelp ();
160
+ return 1 ;
161
+ }
162
+
163
+ std::vector<std::string> inputVec;
164
+ readInput (argv[2 ], std::back_inserter (inputVec));
165
+
166
+ if (task == " part1" ) {
167
+ std::cout << solveFirstPart (inputVec);
168
+ }
169
+ else {
170
+ std::cout << solveSecondPart (inputVec);
171
+ }
172
+
173
+ return 0 ;
174
+ }
0 commit comments