Day14
This commit is contained in:
149
day14/sand.c
Normal file
149
day14/sand.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BUFFER_SIZE 512
|
||||
#define MAX_ROCK_NUMBER 16*1024
|
||||
#define FLOOR_OFFSET 2
|
||||
#define EDGE_BUFFER 256
|
||||
#define min(a, b) (a <= b ? a : b)
|
||||
#define max(a, b) (a >= b ? a : b)
|
||||
// Use this setting to switch between task 1 and task 2
|
||||
#define ENABLE_FLOOR 1
|
||||
|
||||
typedef struct point {
|
||||
int x;
|
||||
int y;
|
||||
} POINT;
|
||||
|
||||
void buildPath(POINT, POINT, POINT*, int*);
|
||||
POINT nextFall(int, int *[*], POINT);
|
||||
|
||||
int main() {
|
||||
char buf[BUFFER_SIZE], *p, c;
|
||||
memset(buf, 0, BUFFER_SIZE);
|
||||
p = buf;
|
||||
POINT bedrock[MAX_ROCK_NUMBER], prev, curr;
|
||||
int bedrock_count = 0;
|
||||
int maxX = 0, maxY = 0, x, y;
|
||||
|
||||
// Read input
|
||||
while ((c = getchar()) != EOF) {
|
||||
*p++ = c;
|
||||
if (c == '\n') {
|
||||
p = buf;
|
||||
sscanf(p, "%i,%i", &x, &y);
|
||||
prev.x = x;
|
||||
prev.y = y;
|
||||
while (*p++ != ' ') {}
|
||||
while(*p != 0) {
|
||||
sscanf(p, "-> %i,%i", &x, &y);
|
||||
if (x > maxX) maxX = x;
|
||||
if (y > maxY) maxY = y;
|
||||
curr.x = x;
|
||||
curr.y = y;
|
||||
|
||||
buildPath(prev, curr, bedrock, &bedrock_count);
|
||||
|
||||
prev.x = x;
|
||||
prev.y = y;
|
||||
while (*p++ != ' ') {}
|
||||
while (*p != ' ' && *p != 0) p++;
|
||||
p++;
|
||||
}
|
||||
|
||||
memset(buf, 0, BUFFER_SIZE);
|
||||
p = buf;
|
||||
}
|
||||
}
|
||||
|
||||
POINT source = { .x = 500, .y = 0 }, sand;
|
||||
|
||||
// Allocate memory for the map
|
||||
int **map = (int**)malloc((maxX + 1 + EDGE_BUFFER) * sizeof(int*));
|
||||
for (int i = 0; i < maxX + 1 + EDGE_BUFFER; i++) {
|
||||
map[i] = (int*)malloc((maxY + FLOOR_OFFSET) * sizeof(int));
|
||||
memset(map[i], 0, (maxY + FLOOR_OFFSET) * sizeof(int));
|
||||
}
|
||||
|
||||
// Fill in the map with bedrock
|
||||
for (int i = 0; i < bedrock_count; i++) {
|
||||
map[bedrock[i].x][bedrock[i].y] = 1;
|
||||
}
|
||||
|
||||
int fallthrough = 0, sum = 0;
|
||||
POINT fallPosition;
|
||||
|
||||
// Play until sand falls through
|
||||
while (!fallthrough) {
|
||||
// Simulate each sand
|
||||
sand.x = source.x;
|
||||
sand.y = source.y;
|
||||
|
||||
do {
|
||||
fallPosition = nextFall(maxY + FLOOR_OFFSET, map, sand);
|
||||
|
||||
// We fell through the map
|
||||
if (fallPosition.x == -2) {
|
||||
fallthrough = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// We hit bedrock
|
||||
if (fallPosition.x == -1) {
|
||||
sum += 1;
|
||||
map[sand.x][sand.y] = 2;
|
||||
// Source gets clogged
|
||||
if (sand.x == source.x && sand.y == source.y) {
|
||||
fallthrough = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sand = fallPosition;
|
||||
} while(fallPosition.x != -1);
|
||||
}
|
||||
|
||||
printf("%i\n", sum);
|
||||
}
|
||||
|
||||
void buildPath(POINT prev, POINT curr, POINT* bedrock, int* bedrock_count) {
|
||||
if (prev.x != curr.x) {
|
||||
for (int i = min(prev.x, curr.x); i <= max(prev.x, curr.x); i++) {
|
||||
bedrock[*bedrock_count].x = i;
|
||||
bedrock[*bedrock_count].y = prev.y;
|
||||
(*bedrock_count)++;
|
||||
}
|
||||
} else if (prev.y != curr.y) {
|
||||
for (int i = min(prev.y, curr.y); i <= max(prev.y, curr.y); i++) {
|
||||
bedrock[*bedrock_count].x = prev.x;
|
||||
bedrock[*bedrock_count].y = i;
|
||||
(*bedrock_count)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
POINT nextFall(int mapHeight, int *map[mapHeight], POINT point) {
|
||||
POINT end = { .x = -1, .y = -1 };
|
||||
|
||||
if (point.y == mapHeight - FLOOR_OFFSET && !ENABLE_FLOOR) {
|
||||
// Fall out of the map
|
||||
end.x = -2;
|
||||
end.y = -2;
|
||||
} else if (ENABLE_FLOOR && point.y == mapHeight - 1) {
|
||||
// Fall on floor
|
||||
} else if (map[point.x][point.y+1] == 0) {
|
||||
// Fall straight down
|
||||
end.x = point.x;
|
||||
end.y = point.y + 1;
|
||||
} else if (map[point.x - 1][point.y + 1] == 0) {
|
||||
// Fall left down
|
||||
end.x = point.x - 1;
|
||||
end.y = point.y + 1;
|
||||
} else if (map[point.x + 1][point.y + 1] == 0) {
|
||||
// Fall right down
|
||||
end.x = point.x + 1;
|
||||
end.y = point.y + 1;
|
||||
}
|
||||
|
||||
return end;
|
||||
}
|
||||
Reference in New Issue
Block a user