#include #include #include #include #include "../../lib/aoc.h" struct Map; typedef struct Region { struct Map *map; char plant; int positions[1000]; int positions_count; } Region; typedef struct Map { char *data; int width; int height; int input_length; Region regions[1000]; int regions_count; } Map; int region_perimeter(Region *r) { int perimeter = 0; for (int i = 0; i < r->positions_count; i++) { int position = r->positions[i]; if (position - r->map->width < 0 || r->map->data[position - r->map->width] != r->plant - 'A' + 'a') { perimeter++; } if (position - 1 < 0 || r->map->data[position - 1] != r->plant - 'A' + 'a') { perimeter++; } if (position + 1 > r->map->input_length || r->map->data[position + 1] != r->plant - 'A' + 'a') { perimeter++; } if (position + r->map->width > r->map->input_length || r->map->data[position + r->map->width] != r->plant - 'A' + 'a') { perimeter++; } } return perimeter; } int region_inner_corner_count(Region *r) { int inner_corners = 0; for (int i = 0; i < r->positions_count; i++) { int position = r->positions[i]; bool up = false, down = false, left = false, right = false; bool up_left = false, down_left = false, up_right = false, down_right = false; if (position - r->map->width - 1 >= 0 && r->map->data[position - r->map->width - 1] == r->plant - 'A' + 'a') { up_left = true; } if (position - r->map->width >= 0 && r->map->data[position - r->map->width] == r->plant - 'A' + 'a') { up = true; } if (position - r->map->width + 1 >= 0 && r->map->data[position - r->map->width + 1] == r->plant - 'A' + 'a') { up_right = true; } if (position - 1 > 0 && r->map->data[position - 1] == r->plant - 'A' + 'a') { left = true; } if (position + 1 < r->map->input_length && r->map->data[position + 1] == r->plant - 'A' + 'a') { right = true; } if (position + r->map->width - 1 < r->map->input_length && r->map->data[position + r->map->width - 1] == r->plant - 'A' + 'a') { down_left = true; } if (position + r->map->width < r->map->input_length && r->map->data[position + r->map->width] == r->plant - 'A' + 'a') { down = true; } if (position + r->map->width + 1 < r->map->input_length && r->map->data[position + r->map->width + 1] == r->plant - 'A' + 'a') { down_right = true; } if (up && left && !up_left) inner_corners++; if (up && right && !up_right) inner_corners++; if (down && left && !down_left) inner_corners++; if (down && right && !down_right) inner_corners++; } return inner_corners; } int region_outer_corner_count(Region *r) { int outer_corners = 0; for (int i = 0; i < r->positions_count; i++) { int position = r->positions[i]; bool top_fence = false, left_fence = false, right_fence = false, bottom_fence = false; if (position - r->map->width < 0 || r->map->data[position - r->map->width] != r->plant - 'A' + 'a') { top_fence = true; } if (position - 1 < 0 || r->map->data[position - 1] != r->plant - 'A' + 'a') { left_fence = true; } if (position + 1 > r->map->input_length || r->map->data[position + 1] != r->plant - 'A' + 'a') { right_fence = true; } if (position + r->map->width > r->map->input_length || r->map->data[position + r->map->width] != r->plant - 'A' + 'a') { bottom_fence = true; } if (top_fence && left_fence) outer_corners++; if (bottom_fence && left_fence) outer_corners++; if (top_fence && right_fence) outer_corners++; if (bottom_fence && right_fence) outer_corners++; } return outer_corners; } int region_price(Region *r) { return region_perimeter(r) * r->positions_count; } int region_price_2(Region *r) { int roc = region_outer_corner_count(r); int ric = region_inner_corner_count(r); return (roc + ric) * r->positions_count; } int main() { char *input = aoc_read_input(); int input_length = strlen(input); Map m; fflush(stdout); m.data = input; m.width = strchr(input, '\n') - input + 1; m.height = input_length / m.width; m.regions_count = 0; m.input_length = input_length; // initialize regions for (int i = 0; i < input_length; i++) { if (m.data[i] == '\n' || m.data[i] < 'A' || m.data[i] > 'Z') continue; Region *r = &(m.regions[m.regions_count++]); r->plant = m.data[i]; r->positions_count = 0; r->map = &m; int next_positions[1000]; next_positions[0] = i; int next_positions_count = 1; int nn_positions[1000]; int nn_positions_count = 0; while (next_positions_count > 0) { for (int j = 0; j < next_positions_count; j++) { int next_position = next_positions[j]; r->positions[r->positions_count++] = next_position; m.data[next_position] = m.data[next_position] - 'A' + 'a'; } for (int j = 0; j < next_positions_count; j++) { int next_position = next_positions[j]; if (next_position - m.width > 0 && m.data[next_position - m.width] == r->plant) { nn_positions[nn_positions_count++] = next_position - m.width; } if (next_position - 1 > 0 && m.data[next_position - 1] == r->plant) { nn_positions[nn_positions_count++] = next_position - 1; } if (next_position + 1 < input_length && m.data[next_position + 1] == r->plant) { nn_positions[nn_positions_count++] = next_position + 1; } if (next_position + m.width < input_length && m.data[next_position + m.width] == r->plant) { nn_positions[nn_positions_count++] = next_position + m.width; } } qsort(nn_positions, nn_positions_count, sizeof(int), aoc_sort_int); if (nn_positions_count == 0) break; next_positions_count = 1; next_positions[0] = nn_positions[0]; for (int j = 1; j < nn_positions_count; j++) { if (nn_positions[j] != next_positions[next_positions_count - 1]) { next_positions[next_positions_count++] = nn_positions[j]; } } nn_positions_count = 0; } } int cost = 0; int cost_2 = 0; for (int i = 0; i < m.regions_count; i++) { cost += region_price(&m.regions[i]); cost_2 += region_price_2(&m.regions[i]); } printf("Part 1: %d\n", cost); printf("Part 2: %d\n", cost_2); aoc_free(); return 0; }