83 lines
3.1 KiB
C
83 lines
3.1 KiB
C
#include "aoc.h"
|
|
|
|
const int dx[] = {0, 1, 0, -1};
|
|
const int dy[] = {-1, 0, 1, 0};
|
|
|
|
static inline bool
|
|
inside(Grid *grid, int x, int y) {
|
|
return x >= 0 && y >= 0 && x < grid->width && y < grid->height;
|
|
}
|
|
|
|
static inline bool
|
|
unequal_or_outside(Grid *grid, int x, int y, char type) {
|
|
if (inside(grid, x, y)) {
|
|
return grid->grid[y * grid->width + x] != type;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static void
|
|
flood_fill(Grid *grid, bool *visited, int x, int y, int *area, int *perimeter, int *sides) {
|
|
if (visited[y * grid->width + x]) {
|
|
return;
|
|
}
|
|
|
|
char type = grid->grid[y * grid->width + x];
|
|
|
|
(*area)++;
|
|
visited[y * grid->width + x] = true;
|
|
for (int i = 0; i < 4; i++) {
|
|
int nx = x + dx[i];
|
|
int ny = y + dy[i];
|
|
|
|
if (unequal_or_outside(grid, nx, ny, type)) {
|
|
(*perimeter)++;
|
|
}
|
|
else {
|
|
flood_fill(grid, visited, nx, ny, area, perimeter, sides);
|
|
}
|
|
}
|
|
|
|
|
|
// convex corners
|
|
*sides += (unequal_or_outside(grid, x - 1, y, type) && unequal_or_outside(grid, x, y - 1, type)); // top left corner
|
|
*sides += (unequal_or_outside(grid, x + 1, y, type) && unequal_or_outside(grid, x, y - 1, type)); // top right corner
|
|
*sides += (unequal_or_outside(grid, x - 1, y, type) && unequal_or_outside(grid, x, y + 1, type)); // bottom left corner
|
|
*sides += (unequal_or_outside(grid, x + 1, y, type) && unequal_or_outside(grid, x, y + 1, type)); // bottom right corner
|
|
|
|
// concave corners
|
|
*sides += (!unequal_or_outside(grid, x - 1, y, type) && !unequal_or_outside(grid, x - 1, y - 1, type) && unequal_or_outside(grid, x, y - 1, type)); // top left corner
|
|
*sides += (!unequal_or_outside(grid, x + 1, y, type) && !unequal_or_outside(grid, x + 1, y - 1, type) && unequal_or_outside(grid, x, y - 1, type)); // top right corner
|
|
*sides += (!unequal_or_outside(grid, x - 1, y, type) && !unequal_or_outside(grid, x - 1, y + 1, type) && unequal_or_outside(grid, x, y + 1, type)); // bottom left corner
|
|
*sides += (!unequal_or_outside(grid, x + 1, y, type) && !unequal_or_outside(grid, x + 1, y + 1, type) && unequal_or_outside(grid, x, y + 1, type)); // bottom right corner
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
Arena *arena = make_arena(Megabytes(1));
|
|
str input = read_file(arena, argv[1]);
|
|
Grid grid = parse_grid(input, arena);
|
|
|
|
bool *visited = ARENA_ALLOC_ARRAY(arena, bool, grid.width * grid.height);
|
|
|
|
i64 part_1 = 0;
|
|
i64 part_2 = 0;
|
|
for (int y = 0; y < grid.height; y++) {
|
|
for (int x = 0; x < grid.width; x++) {
|
|
if (!visited[y * grid.width + x]) {
|
|
int area = 0;
|
|
int perimeter = 0;
|
|
int sides = 0;
|
|
flood_fill(&grid, visited, x, y, &area, &perimeter, &sides);
|
|
char type = grid.grid[y * grid.width + x];
|
|
/* printf("type = %c, area = %d, perimeter = %d, sides = %d\n", type, area, perimeter, sides); */
|
|
part_1 += area * perimeter;
|
|
part_2 += area * sides;
|
|
}
|
|
}
|
|
}
|
|
printf("%ld\n", part_1);
|
|
printf("%ld\n", part_2);
|
|
}
|