aoc24/12/main.cc
2024-12-12 15:04:28 +01:00

180 lines
5.6 KiB
C++

#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <tuple>
#include <set>
using namespace std;
#ifdef DEBUG
#define DBG(str) do { std::cout << str << std::endl; } while( false )
#else
#define DBG(str) do { } while ( false )
#endif
vector<vector<char>> parseGrid(const char *path) {
vector<vector<char>> grid;
ifstream input(path);
string line;
while (getline(input, line)) {
char c;
vector<char> row;
stringstream ss;
ss << line;
while (ss >> c) {
row.push_back(c);
}
grid.push_back(row);
}
return grid;
}
void printGrid(vector<vector<char>> grid) {
for (int y = 0; y < grid.size(); y++) {
for (int x = 0; x < grid[0].size(); x++) {
cout << grid[y][x];
}
cout << endl;
}
}
void plotScore(vector<vector<char>> grid, set<tuple<int,int>> &visited, int x, int y, char c, int &perimeter, int &size) {
if (visited.count(make_tuple(x,y))) return;
visited.insert(make_tuple(x,y));
size++;
// above
if (y == 0 || grid[y - 1][x] != c) {
perimeter++;
} else if (!visited.count(make_tuple(x,y - 1))) {
plotScore(grid, visited, x, y - 1, c, perimeter, size);
}
// below
if (y == grid.size() - 1 || grid[y + 1][x] != c) {
perimeter++;
} else if (!visited.count(make_tuple(x,y + 1))) {
plotScore(grid, visited, x, y + 1, c, perimeter, size);
}
// left
if (x == 0 || grid[y][x - 1] != c) {
perimeter++;
} else if (!visited.count(make_tuple(x - 1,y))) {
plotScore(grid, visited, x - 1, y, c, perimeter, size);
}
// right
if (x == grid[0].size() - 1 || grid[y][x + 1] != c) {
perimeter++;
} else if (!visited.count(make_tuple(x + 1,y))) {
plotScore(grid, visited, x + 1, y, c, perimeter, size);
}
}
enum position {
TL,
TR,
BL,
BR
};
void plotScoreCheaper(vector<vector<char>> grid, set<tuple<int,int>> &visited, set<tuple<int,int,position>> &visited_corners, int x, int y, char c, int &sides, int &size) {
if (visited.count(make_tuple(x,y))) return;
visited.insert(make_tuple(x,y));
size++;
// check if grid[y][x] is a corner, since #corners == #sides
/// top left
if (!visited_corners.count(make_tuple(x, y, TL)) &&
((x == 0 || grid[y][x - 1] != c) && (y == 0 || grid[y - 1][x] != c) // outer corner
|| (x > 0 && y > 0 && grid[y][x - 1] == c && grid[y - 1][x] == c && grid[y - 1][x - 1] != c))) // inner corner
{
sides++;
visited_corners.insert(make_tuple(x, y, TL));
}
/// bottom left
if (!visited_corners.count(make_tuple(x, y, BL)) &&
((x == 0 || grid[y][x - 1] != c) && (y == grid.size() - 1 || grid[y + 1][x] != c)) // outer corner
|| (x > 0 && y < grid.size() - 1 && grid[y][x - 1] == c && grid[y + 1][x] == c && grid[y + 1][x - 1] != c)) // inner corner
{
sides++;
visited_corners.insert(make_tuple(x, y, BL));
}
/// top right
if (!visited_corners.count(make_tuple(x, y, TR)) &&
((x == grid[y].size() - 1 || grid[y][x + 1] != c) && (y == 0 || grid[y - 1][x] != c)) // outer corner
|| (x < grid[y].size() - 1 && y > 0 && grid[y][x + 1] == c && grid[y - 1][x] == c && grid[y - 1][x + 1] != c)) // inner corner
{
sides++;
visited_corners.insert(make_tuple(x, y, TR));
}
/// bottom right
if (!visited_corners.count(make_tuple(x, y, BR)) &&
((x == grid[y].size() - 1 || grid[y][x + 1] != c) && (y == grid.size() - 1 || grid[y + 1][x] != c)) // outer corner
|| (x < grid[y].size() - 1 && y < grid.size() - 1 && grid[y][x + 1] == c && grid[y + 1][x] == c && grid[y + 1][x + 1] != c)) // inner corner
{
sides++;
visited_corners.insert(make_tuple(x, y, BR));
}
// now recurse on all 4 sides
if (y > 0 && !visited.count(make_tuple(x, y - 1)) && grid[y - 1][x] == c) {
plotScoreCheaper(grid, visited, visited_corners, x, y - 1, c, sides, size);
}
if (y < grid.size() - 1 && !visited.count(make_tuple(x, y + 1)) && grid[y + 1][x] == c) {
plotScoreCheaper(grid, visited, visited_corners, x, y + 1, c, sides, size);
}
if (x > 0 && !visited.count(make_tuple(x - 1, y)) && grid[y][x - 1] == c) {
plotScoreCheaper(grid, visited, visited_corners, x - 1, y, c, sides, size);
}
if (x < grid[y].size() - 1 && !visited.count(make_tuple(x + 1, y)) && grid[y][x + 1] == c) {
plotScoreCheaper(grid, visited, visited_corners, x + 1, y, c, sides, size);
}
}
int part1(const char *path) {
vector<vector<char>> grid = parseGrid(path);
int ret = 0;
set<tuple<int,int>> visited;
for (int y = 0; y < grid.size(); y++) {
for (int x = 0; x < grid[y].size(); x++) {
int perimeter = 0;
int size = 0;
plotScore(grid, visited, x, y, grid[y][x], perimeter, size);
ret += perimeter * size;
}
}
return ret;
}
int part2(const char *path) {
vector<vector<char>> grid = parseGrid(path);
set<tuple<int,int,position>> visited_corners;
int ret = 0;
set<tuple<int,int>> visited;
for (int y = 0; y < grid.size(); y++) {
for (int x = 0; x < grid[y].size(); x++) {
int sides = 0;
int size = 0;
plotScoreCheaper(grid, visited, visited_corners, x, y, grid[y][x], sides, size);
if (sides != 0) DBG("visited " << grid[y][x] << " got sides=" << sides << " and size=" << size << " result=" << sides * size << endl);
ret += sides * size;
}
}
return ret;
}
int main(int argc, char *argv[]) {
cout << "example1: " << part1("example") << endl;
cout << "input1: " << part1("input") << endl;
cout << "example2: " << part2("example") << endl;
cout << "input2: " << part2("input") << endl;
return 0;
}