2018/Day17/Day17A.c

198 lines
5.9 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <assert.h>
#include <string.h>
#define AT(x, y) grid[(y) * x_max + (x)]
void get_limits(FILE *file, int *x_min, int *x_max, int *y_min, int *y_max) {
char *line = NULL;
size_t len;
*x_min = INT_MAX;
*x_max = INT_MAX;
*x_max = 0;
*y_max = 0;
while (getline(&line, &len, file) != -1) {
int xa, xb, ya, yb;
if (sscanf(line, "x=%d, y=%d..%d", &xa, &ya, &yb) == 3) {
if (xa < *x_min) *x_min = xa;
if (xa + 1 > *x_max) *x_max = xa + 1;
if (ya < *y_min) *y_min = ya;
if (yb + 1 > *y_max) *y_max = yb + 1;
} else if (sscanf(line, "y=%d, x=%d..%d", &ya, &xa, &xb) == 3) {
if (xa < *x_min) *x_min = xa;
if (xb + 1 > *x_max) *x_max = xa + 1;
if (ya < *y_min) *y_min = ya;
if (ya + 1 > *y_max) *y_max = yb + 1;
} else {
break;
}
}
*x_max += 10;
*x_min -= 10;
printf("grid: x=%d..%d y=%d..%d\n", *x_min, *x_max, *y_min, *y_max);
rewind(file);
}
void build_grid(FILE *file, char *grid, int x_max) {
char *line = NULL;
size_t len;
while (getline(&line, &len, file) != -1) {
int xa, xb, ya, yb;
if (sscanf(line, "x=%d, y=%d..%d", &xa, &ya, &yb) == 3) {
printf("x=%d, y=%d..%d\n", xa, ya, yb);
for (int y = ya; y <= yb; y++)
AT(xa, y) = '#';
} else if (sscanf(line, "y=%d, x=%d..%d", &ya, &xa, &xb) == 3) {
printf("x=%d..%d, y=%d\n", xa, xb, ya);
for (int x = xa; x <= xb; x++)
AT(x, ya) = '#';
} else {
break;
}
}
grid[500] = '+';
}
void print_grid(char *grid, int x_min, int x_max, int y_min, int y_max) {
printf("\n");
printf(" "); for (int x = x_min; x < x_max; x++) printf("%d", x / 100 % 10); printf("\n");
printf(" "); for (int x = x_min; x < x_max; x++) printf("%d", x / 10 % 10); printf("\n");
printf(" "); for (int x = x_min; x < x_max; x++) printf("%d", x % 10); printf("\n");
for (int y = 0; y < y_max + 3; y++) {
if (y < y_min || y >= y_max)
printf("\033[41m");
printf("%4d \033[0m", y);
for (int x = x_min; x < x_max; x++) {
switch (grid[y * x_max + x]) {
case '.':
putchar(' ');
putchar(' ');
break;
case '|':
printf("\033[44m\u2551\u2551\033[0m");
break;
case '~':
printf("\033[44m\u2248\u2248\033[0m");
break;
case '#':
printf("\033[33m\u2588\u2588\033[0m");
break;
case '+':
printf("\033[41m\u256C\u256C\033[0m");
break;
default:
assert(0);
}
}
putchar('\n');
}
}
char *read_grid(FILE *file, int *x_min, int *x_max, int *y_min, int *y_max) {
get_limits(file, x_min, x_max, y_min, y_max);
size_t size = (*y_max + 50) * *x_max;
char *grid = malloc(size);
memset(grid, '.', size);
build_grid(file, grid, *x_max);
return grid;
}
void step(char *grid, int x_min, int x_max, int y_min, int y_max) {
for (int y = 0; y < y_max + 50; y++) {
for (int x = x_min; x < x_max; x++) {
if (AT(x, y) == '+' || AT(x, y) == '|') {
if (AT(x, y + 1) == '.') {
AT(x, y + 1) = '|';
} else if (AT(x, y + 1) == '#' || AT(x, y + 1) == '~') {
int is_still = 1;
int left_wall = -1, right_wall = -1;
for (int x_ = x; x_ >= x_min - 1; x_--) {
if (AT(x_, y) == '#') {
left_wall = x_ + 1;
break;
} else if (AT(x_, y + 1) == '.' || AT(x_, y + 1) == '|') {
is_still = 0;
left_wall = x_;
break;
}
}
for (int x_ = x; x_ <= x_max; x_++) {
if (AT(x_, y) == '#') {
right_wall = x_ - 1;
break;
} else if (AT(x_, y + 1) == '.' || AT(x_, y + 1) == '|') {
is_still = 0;
right_wall = x_;
break;
}
}
if (left_wall != -1 && right_wall != -1) {
for (int x_ = left_wall; x_ <= right_wall; x_++) {
assert(AT(x_, y) != '#');
AT(x_, y) = is_still ? '~' : '|';
}
}
}
}
}
}
}
int count_water(char *grid, int x_min, int x_max, int y_min, int y_max) {
int water = 0;
for (int y = y_min; y < y_max; y++) {
for (int x = x_min; x < x_max; x++) {
water += (AT(x, y) == '~') ? 1 : 0;
}
}
return water;
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("Usage: %s [input]\n", argv[0]);
return EXIT_FAILURE;
}
FILE *file = fopen(argv[1], "r");
int x_min, x_max, y_min, y_max;
char *grid = read_grid(file, &x_min, &x_max, &y_min, &y_max);
print_grid(grid, x_min, x_max, y_min, y_max);
int last_water = -1, water = -1;
int extra_steps = 0;
do {
step(grid, x_min, x_max, y_min, y_max);
last_water = water;
water = count_water(grid, x_min, x_max, y_min, y_max);
printf("Water: %d\r", water);
if (last_water == water)
extra_steps += 1;
else
extra_steps = 0;
} while (extra_steps < 200);
print_grid(grid, x_min, x_max, y_min, y_max);
printf("Water: %d\n", water);
}