aboutsummaryrefslogtreecommitdiff
path: root/2024/12/day12b.cpp
diff options
context:
space:
mode:
Diffstat (limited to '2024/12/day12b.cpp')
-rw-r--r--2024/12/day12b.cpp159
1 files changed, 159 insertions, 0 deletions
diff --git a/2024/12/day12b.cpp b/2024/12/day12b.cpp
new file mode 100644
index 0000000..4078fa7
--- /dev/null
+++ b/2024/12/day12b.cpp
@@ -0,0 +1,159 @@
1#include <iostream>
2#include <cstdint>
3#include <algorithm>
4#include <string>
5#include <string_view>
6#include <vector>
7#include <set>
8using namespace std;
9
10class Direction {
11public:
12 const int U, R;
13
14 Direction(const int i, const int j) : U{ i }, R{ j } {}
15
16 Direction turnright() const {
17 return turn(-1, 0);
18 }
19
20 Direction turnleft() const {
21 return turn(1, 0);
22 }
23
24 bool operator<(const Direction& d) const { // For set<Direction>
25 return this->U < d.U || (this->U == d.U && this->R < d.R);
26 }
27private:
28 Direction turn(int64_t sin, int64_t cos) const {
29 return Direction(cos * U - sin * R, sin * U + cos * R);
30 }
31};
32
33class Position {
34public:
35 int64_t i, j;
36
37 Position(int64_t a, int64_t b) : i{a}, j{b} {}
38
39 Position step(const Direction d) const {
40 return Position(i+d.U, j+d.R);
41 }
42};
43
44const Direction all_directions[] = {
45 Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1)
46};
47
48class Board {
49public:
50 int64_t N, M;
51 vector<int64_t> region_area;
52
53 Board(const vector<string>& lines) :
54 N{static_cast<int64_t>(lines.size())},
55 M{static_cast<int64_t>(lines[0].size())},
56 region_area(M*N), cells(M*N), region(M*N), visited(M*N)
57 {
58 for (int64_t i = 0; i < N; i++) {
59 for (int64_t j = 0; j < M; j++) {
60 region[N*i+j] = -1;
61 cells[N*i+j] = lines[i][j];
62 }
63 }
64 }
65
66 char& operator[](const Position p) {
67 if (const auto c = coord(p); c == -1)
68 return out_of_bound;
69 else
70 return cells[c];
71 }
72
73 int64_t& reg(const Position p) {
74 if (const auto c = coord(p); c == -1)
75 return out_of_region;
76 else
77 return region[c];
78 }
79
80 void fill(const Position p, const int64_t r) {
81 reg(p) = r;
82 region_area[r]++;
83 for (const auto d : all_directions)
84 if (auto q = p.step(d);
85 (*this)[q] == (*this)[p] && reg(q) != r)
86 fill(q, r);
87 }
88
89 int64_t compute_perim(int64_t r) {
90 int count = 0;
91 for (Position p(0, 0); p.i < N; p.i++)
92 for (p.j = 0; p.j < M; p.j++)
93 for (Direction d : all_directions)
94 if (reg(p) == r && reg(p.step(d)) != r)
95 count += walk(p, d);
96
97 return count;
98 }
99
100private:
101 char out_of_bound = '$';
102 int64_t out_of_region = -1;
103
104 vector<char> cells;
105 vector<int64_t> region;
106 vector<set<Direction>> visited;
107
108 int64_t coord(const Position p) const {
109 auto [i, j] = p;
110 return i >= N || i < 0 || j >= M || j < 0 ? -1 : N * i + j;
111 }
112
113 bool is_visited(const Position p, const Direction d) const {
114 if (auto c = coord(p); c == -1)
115 return false;
116 else
117 return visited[c].count(d) > 0;
118 }
119
120 void set_visited(const Position p, const Direction d) {
121 if (auto c = coord(p); c != -1)
122 visited[c].insert(d);
123 }
124
125 int64_t walk(const Position p, const Direction d) {
126 const auto r = reg(p);
127 for (auto q = p; reg(q) == r && reg(q.step(d)) != r;
128 q = q.step(d.turnleft())) {
129 if (is_visited(q, d))
130 return 0;
131 set_visited(q, d);
132 }
133
134 return 1;
135 }
136};
137
138int main() {
139 string line;
140 vector<string> lines;
141 while (getline(cin, line))
142 lines.push_back(line);
143
144 Board board(lines);
145
146 int64_t r = 0;
147 for (Position p(0, 0); p.i < board.N; p.i++)
148 for (p.j = 0; p.j < board.M; p.j++)
149 if (board.reg(p) == -1)
150 board.fill(p, r++);
151
152 int64_t tot = 0;
153 for (int64_t i = 0; i < r; i++)
154 tot += board.region_area[i] * board.compute_perim(i);
155
156 cout << tot << endl;
157
158 return 0;
159}

Generated with cgit - Back to sebastiano.tronto.net