#include #include #include #include #include #include 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> parseGrid(const char *path) { vector> grid; ifstream input(path); string line; while (getline(input, line)) { char c; vector row; stringstream ss; ss << line; while (ss >> c) { row.push_back(c); } grid.push_back(row); } return grid; } void printGrid(vector> 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> grid, set> &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> grid, set> &visited, set> &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> grid = parseGrid(path); int ret = 0; set> 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> grid = parseGrid(path); set> visited_corners; int ret = 0; set> 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; }