Day18 C
This commit is contained in:
369
day18/c/day18.c
Normal file
369
day18/c/day18.c
Normal file
@@ -0,0 +1,369 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define LINE_MAX_LENGTH 256
|
||||
#define MAX_ENTRIES 2048
|
||||
#define MAX_QUEUE_LEN 256
|
||||
#define MAX_EDGES 1024
|
||||
#define MAX_BREAKPOINTS 512
|
||||
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
typedef struct entry {
|
||||
char direction;
|
||||
long long count;
|
||||
char rgb_string[10];
|
||||
} entry_t;
|
||||
|
||||
typedef struct zone {
|
||||
long long upper_left_corner[2];
|
||||
long long lower_right_corner[2];
|
||||
uint8_t outside;
|
||||
} zone_t;
|
||||
|
||||
int cmp(const void* a, const void* b);
|
||||
int on_edge(long long edges[MAX_EDGES][2][2], int edges_num, long long side[2][2]);
|
||||
unsigned long long lake_volume(entry_t entries[], int entries_num);
|
||||
void decode_rgbs(entry_t entries[], int entries_num);
|
||||
|
||||
int main() {
|
||||
char *p, *buf, c;
|
||||
|
||||
buf = (char *)malloc(LINE_MAX_LENGTH);
|
||||
memset(buf, 0, LINE_MAX_LENGTH);
|
||||
p = buf;
|
||||
|
||||
entry_t entries[MAX_ENTRIES];
|
||||
memset(entries, 0, MAX_ENTRIES * sizeof(entry_t));
|
||||
int entries_num = 0;
|
||||
|
||||
while ((c = getchar()) != EOF) {
|
||||
*p++ = c;
|
||||
if (c == '\n') {
|
||||
sscanf(buf, "%c %lli %s", &entries[entries_num].direction, &entries[entries_num].count, entries[entries_num].rgb_string);
|
||||
entries_num++;
|
||||
memset(buf, 0, LINE_MAX_LENGTH);
|
||||
p = buf;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long part1 = lake_volume(entries, entries_num);
|
||||
|
||||
decode_rgbs(entries, entries_num);
|
||||
|
||||
unsigned long long part2 = lake_volume(entries, entries_num);
|
||||
|
||||
printf("%llu\n", part1);
|
||||
printf("%llu\n", part2);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
int cmp(const void* a, const void* b) {
|
||||
return *(long long*)a - *(long long*)b;
|
||||
}
|
||||
|
||||
int on_edge(long long edges[MAX_EDGES][2][2], int edges_num, long long side[2][2]) {
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
if (edges[i][0][0] == side[0][0] && edges[i][0][0] == edges[i][1][0] && side[0][0] == side[1][0] && edges[i][0][1] <= side[0][1] && edges[i][1][1] >= side[1][1]) {
|
||||
return 1;
|
||||
}
|
||||
if (edges[i][0][1] == side[0][1] && edges[i][0][1] == edges[i][1][1] && side[0][1] == side[1][1] && edges[i][0][0] <= side[0][0] && edges[i][1][0] >= side[1][0]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long long lake_volume(entry_t entries[], int entries_num) {
|
||||
long long x = 0, y = 0, dir[2];
|
||||
|
||||
long long edges[MAX_EDGES][2][2];
|
||||
memset(edges, 0, MAX_EDGES * 2 * 2 * sizeof(long long));
|
||||
int edges_num = 0;
|
||||
|
||||
for (int i = 0; i < entries_num; i++) {
|
||||
switch (entries[i].direction) {
|
||||
case 'R':
|
||||
dir[0] = 1;
|
||||
dir[1] = 0;
|
||||
edges[edges_num][0][0] = x;
|
||||
edges[edges_num][0][1] = y;
|
||||
edges[edges_num][1][0] = x + entries[i].count * dir[0];
|
||||
edges[edges_num][1][1] = y + entries[i].count * dir[1];
|
||||
edges_num++;
|
||||
break;
|
||||
case 'L':
|
||||
dir[0] = -1;
|
||||
dir[1] = 0;
|
||||
edges[edges_num][1][0] = x;
|
||||
edges[edges_num][1][1] = y;
|
||||
edges[edges_num][0][0] = x + entries[i].count * dir[0];
|
||||
edges[edges_num][0][1] = y + entries[i].count * dir[1];
|
||||
edges_num++;
|
||||
break;
|
||||
case 'U':
|
||||
dir[0] = 0;
|
||||
dir[1] = -1;
|
||||
edges[edges_num][1][0] = x;
|
||||
edges[edges_num][1][1] = y;
|
||||
edges[edges_num][0][0] = x + entries[i].count * dir[0];
|
||||
edges[edges_num][0][1] = y + entries[i].count * dir[1];
|
||||
edges_num++;
|
||||
break;
|
||||
case 'D':
|
||||
dir[0] = 0;
|
||||
dir[1] = 1;
|
||||
edges[edges_num][0][0] = x;
|
||||
edges[edges_num][0][1] = y;
|
||||
edges[edges_num][1][0] = x + entries[i].count * dir[0];
|
||||
edges[edges_num][1][1] = y + entries[i].count * dir[1];
|
||||
edges_num++;
|
||||
break;
|
||||
}
|
||||
|
||||
x += entries[i].count * dir[0];
|
||||
y += entries[i].count * dir[1];
|
||||
}
|
||||
|
||||
// Find smallest and largest x and y
|
||||
long long min_x = LLONG_MAX, max_x = LLONG_MIN, min_y = LLONG_MAX, max_y = LLONG_MIN;
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
if (edges[i][0][0] < min_x) {
|
||||
min_x = edges[i][0][0];
|
||||
}
|
||||
if (edges[i][1][0] > max_x) {
|
||||
max_x = edges[i][1][0];
|
||||
}
|
||||
if (edges[i][0][1] < min_y) {
|
||||
min_y = edges[i][0][1];
|
||||
}
|
||||
if (edges[i][1][1] > max_y) {
|
||||
max_y = edges[i][1][1];
|
||||
}
|
||||
}
|
||||
|
||||
// X breakpoints
|
||||
long long x_breakpoints[MAX_BREAKPOINTS], x_breakpoints_num = 0;
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
int found = 0;
|
||||
for (int j = 0; j < x_breakpoints_num; j++) {
|
||||
if (edges[i][0][0] == x_breakpoints[j]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
x_breakpoints[x_breakpoints_num] = edges[i][0][0];
|
||||
x_breakpoints_num++;
|
||||
}
|
||||
found = 0;
|
||||
for (int j = 0; j < x_breakpoints_num; j++) {
|
||||
if (edges[i][1][0] == x_breakpoints[j]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
x_breakpoints[x_breakpoints_num] = edges[i][1][0];
|
||||
x_breakpoints_num++;
|
||||
}
|
||||
}
|
||||
qsort(x_breakpoints, x_breakpoints_num, sizeof(x_breakpoints[0]), &cmp);
|
||||
|
||||
// Y breakpoints
|
||||
long long y_breakpoints[MAX_BREAKPOINTS], y_breakpoints_num = 0;
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
int found = 0;
|
||||
for (int j = 0; j < y_breakpoints_num; j++) {
|
||||
if (edges[i][0][1] == y_breakpoints[j]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
y_breakpoints[y_breakpoints_num] = edges[i][0][1];
|
||||
y_breakpoints_num++;
|
||||
}
|
||||
found = 0;
|
||||
for (int j = 0; j < y_breakpoints_num; j++) {
|
||||
if (edges[i][1][1] == y_breakpoints[j]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
y_breakpoints[y_breakpoints_num] = edges[i][1][1];
|
||||
y_breakpoints_num++;
|
||||
}
|
||||
}
|
||||
qsort(y_breakpoints, y_breakpoints_num, sizeof(y_breakpoints[0]), &cmp);
|
||||
|
||||
zone_t **zones = (zone_t**)malloc((x_breakpoints_num - 1) * sizeof(zone_t*));
|
||||
for (int i = 0; i < x_breakpoints_num - 1; i++) {
|
||||
zones[i] = (zone_t*)malloc((y_breakpoints_num - 1) * sizeof(zone_t));
|
||||
memset(zones[i], 0, (y_breakpoints_num - 1) * sizeof(zone_t));
|
||||
}
|
||||
zone_t *curr;
|
||||
|
||||
for (int i = 0; i < y_breakpoints_num - 1; i++) {
|
||||
for (int j = 0; j < x_breakpoints_num - 1; j++) {
|
||||
curr = &zones[j][i];
|
||||
curr->upper_left_corner[0] = x_breakpoints[j];
|
||||
curr->upper_left_corner[1] = y_breakpoints[i];
|
||||
curr->lower_right_corner[0] = x_breakpoints[j + 1];
|
||||
curr->lower_right_corner[1] = y_breakpoints[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
// Mark zones as outside
|
||||
int found = 1;
|
||||
while (found) {
|
||||
found = 0;
|
||||
for (int i = 0; i < y_breakpoints_num - 1; i++) {
|
||||
for (int j = 0; j < x_breakpoints_num - 1; j++) {
|
||||
if (zones[j][i].outside) {
|
||||
continue;
|
||||
}
|
||||
// LEFT
|
||||
long long side[2][2];
|
||||
side[0][0] = zones[j][i].upper_left_corner[0];
|
||||
side[0][1] = zones[j][i].upper_left_corner[1];
|
||||
side[1][0] = zones[j][i].upper_left_corner[0];
|
||||
side[1][1] = zones[j][i].lower_right_corner[1];
|
||||
if (j == 0 && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
if (j > 0 && zones[j-1][i].outside && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
// RIGHT
|
||||
side[0][0] = zones[j][i].lower_right_corner[0];
|
||||
side[0][1] = zones[j][i].upper_left_corner[1];
|
||||
side[1][0] = zones[j][i].lower_right_corner[0];
|
||||
side[1][1] = zones[j][i].lower_right_corner[1];
|
||||
if (j == x_breakpoints_num - 2 && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
if (j < x_breakpoints_num - 2 && zones[j+1][i].outside && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
// UP
|
||||
side[0][0] = zones[j][i].upper_left_corner[0];
|
||||
side[0][1] = zones[j][i].upper_left_corner[1];
|
||||
side[1][0] = zones[j][i].lower_right_corner[0];
|
||||
side[1][1] = zones[j][i].upper_left_corner[1];
|
||||
if (i == 0 && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
if (i > 0 && zones[j][i-1].outside && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
// DOWN
|
||||
side[0][0] = zones[j][i].upper_left_corner[0];
|
||||
side[0][1] = zones[j][i].lower_right_corner[1];
|
||||
side[1][0] = zones[j][i].lower_right_corner[0];
|
||||
side[1][1] = zones[j][i].lower_right_corner[1];
|
||||
if (i == y_breakpoints_num - 2 && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
if (i < y_breakpoints_num - 2 && zones[j][i+1].outside && !on_edge(edges, edges_num, side)) {
|
||||
zones[j][i].outside = 1;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long sum = 0;
|
||||
unsigned long long out = 0;
|
||||
for (int i = 0; i < y_breakpoints_num - 1; i++) {
|
||||
for (int j = 0; j < x_breakpoints_num - 1; j++) {
|
||||
if (zones[j][i].outside) {
|
||||
out++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < y_breakpoints_num - 1; i++) {
|
||||
for (int j = 0; j < x_breakpoints_num - 1; j++) {
|
||||
if (zones[j][i].outside) {
|
||||
continue;
|
||||
}
|
||||
sum += (zones[j][i].lower_right_corner[0] - zones[j][i].upper_left_corner[0] - 1) * (zones[j][i].lower_right_corner[1] - zones[j][i].upper_left_corner[1] - 1);
|
||||
// RIGHT
|
||||
long long side[2][2];
|
||||
side[0][0] = zones[j][i].lower_right_corner[0];
|
||||
side[0][1] = zones[j][i].upper_left_corner[1];
|
||||
side[1][0] = zones[j][i].lower_right_corner[0];
|
||||
side[1][1] = zones[j][i].lower_right_corner[1];
|
||||
if (!on_edge(edges, edges_num, side)) {
|
||||
sum += side[1][1] - side[0][1] - 1;
|
||||
}
|
||||
// DOWN
|
||||
side[0][1] = zones[j][i].lower_right_corner[1];
|
||||
side[0][0] = zones[j][i].upper_left_corner[0];
|
||||
side[1][0] = zones[j][i].lower_right_corner[0];
|
||||
side[1][1] = zones[j][i].lower_right_corner[1];
|
||||
if (!on_edge(edges, edges_num, side)) {
|
||||
sum += side[1][0] - side[0][0] - 1;
|
||||
}
|
||||
// CORNER
|
||||
side[0][1] = zones[j][i].lower_right_corner[1];
|
||||
side[0][0] = zones[j][i].lower_right_corner[0];
|
||||
side[1][0] = zones[j][i].lower_right_corner[0];
|
||||
side[1][1] = zones[j][i].lower_right_corner[1];
|
||||
if (!on_edge(edges, edges_num, side)) {
|
||||
sum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < edges_num; i++) {
|
||||
sum += (edges[i][1][0] - edges[i][0][0]) + (edges[i][1][1] - edges[i][0][1]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < x_breakpoints_num - 1; i++) {
|
||||
free(zones[i]);
|
||||
}
|
||||
free(zones);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
void decode_rgbs(entry_t entries[], int entries_num) {
|
||||
for (int i = 0; i < entries_num; i++) {
|
||||
char value[6], *p;
|
||||
memset(value, 0, 6);
|
||||
p = entries[i].rgb_string;
|
||||
while(*p != '#') p++;
|
||||
p++;
|
||||
strncpy(value, p, 5);
|
||||
sscanf(value, "%llx", &entries[i].count);
|
||||
switch(entries[i].rgb_string[7]) {
|
||||
case '0':
|
||||
entries[i].direction = 'R';
|
||||
break;
|
||||
case '1':
|
||||
entries[i].direction = 'D';
|
||||
break;
|
||||
case '2':
|
||||
entries[i].direction = 'L';
|
||||
break;
|
||||
case '3':
|
||||
entries[i].direction = 'U';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user