aoc

My solutions for the Advent of Code
git clone https://git.tronto.net/aoc
Download | Log | Files | Refs | README

day12b.cpp (3262B)


      1 #include <iostream>
      2 #include <cstdint>
      3 #include <algorithm>
      4 #include <string>
      5 #include <string_view>
      6 #include <vector>
      7 #include <set>
      8 using namespace std;
      9 
     10 class Direction {
     11 public:
     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 	}
     27 private:
     28 	Direction turn(int64_t sin, int64_t cos) const {
     29 		return Direction(cos * U - sin * R, sin * U + cos * R);
     30 	}
     31 };
     32 
     33 class Position {
     34 public:
     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 
     44 const Direction all_directions[] = {
     45 	Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1)
     46 };
     47 
     48 class Board {
     49 public:
     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[M*i+j] = -1;
     61 				cells[M*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 
    100 private:
    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 : M * 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 
    138 int 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 }