Files
adventofcode2024/day18/c/day18.c
dobiadi da86193181 Day18
2024-12-18 13:26:09 +01:00

230 lines
6.2 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHARS_MAX 6
#define MAX_BYTES 16*1024
#define QUEUE_MAX 16*1024
const int directions[][2] = {
{0, 1},
{1, 0},
{0, -1},
{-1, 0}
};
#define directions_len (sizeof(directions)/sizeof(directions[0]))
int main() {
char *p, *buf, c;
buf = calloc(CHARS_MAX, sizeof(char));
p = buf;
int (*bytes)[2] = calloc(MAX_BYTES, sizeof(bytes[0]));
int byte_count = 0;
while ((c = getchar()) != EOF) {
*p++ = c;
if (c != '\n') {
continue;
}
p = buf;
sscanf(p, "%i", &bytes[byte_count][0]);
while(*p++ != ',');
sscanf(p, "%i", &bytes[byte_count++][1]);
memset(buf, 0, CHARS_MAX);
p = buf;
}
free(buf);
int rows, colums, first_batch;
// Sample vs real life
if (byte_count < 1024) {
rows = 7;
colums = 7;
first_batch = 12;
} else {
rows = 71;
colums = 71;
first_batch = 1024;
}
int **map = calloc(rows, sizeof(map[0]));
for (int i = 0; i < rows; i++) {
map[i] = calloc(colums, sizeof(map[0][0]));
}
// Task 1: First batch of bytes
for (int i = 0; i < first_batch; i++) {
map[bytes[i][1]][bytes[i][0]] = 1;
}
// Shortest path search
uint32_t **costs = calloc(rows, sizeof(costs[0]));
for (int i = 0; i < rows; i++) {
costs[i] = calloc(colums, sizeof(costs[0][0]));
memset(costs[i], 255, colums * sizeof(costs[0][0]));
}
int (*queue)[2] = calloc(QUEUE_MAX, sizeof(queue[0]));
int queue_num = 1;
// Start at 0,0
queue[0][0] = 0;
queue[0][1] = 0;
costs[0][0] = 0;
while (queue_num > 0) {
// Pop first
int x = queue[0][0];
int y = queue[0][1];
uint32_t cost = costs[x][y];
if (x == rows - 1 && y == colums - 1) {
printf("%u\n", cost);
break;
}
for (int i = 0; i < queue_num - 1; i++) {
queue[i][0] = queue[i+1][0];
queue[i][1] = queue[i+1][1];
}
queue_num--;
// Check each direction
for (int i = 0; i < directions_len; i++) {
int dx = directions[i][0];
int dy = directions[i][1];
int next_x = x + dx;
int next_y = y + dy;
// Outside of map, into wall, or better path exists
if (next_x < 0 || next_y < 0 || next_x >= rows || next_y >= colums || map[next_x][next_y] || costs[next_x][next_y] <= cost + 1) {
continue;
}
// Insert into queue
uint32_t next_cost = cost + 1;
costs[next_x][next_y] = next_cost;
int insert_idx;
for (insert_idx = 0; insert_idx < queue_num; insert_idx++) {
int qx = queue[insert_idx][0];
int qy = queue[insert_idx][1];
if (costs[qx][qy] > next_cost) {
break;
}
}
for (int j = queue_num; j > insert_idx; j--) {
queue[j][0] = queue[j-1][0];
queue[j][1] = queue[j-1][1];
}
queue[insert_idx][0] = next_x;
queue[insert_idx][1] = next_y;
queue_num++;
}
}
// Second part
for (int k = 1; k < byte_count; k++) {
int **map = calloc(rows, sizeof(map[0]));
for (int i = 0; i < rows; i++) {
map[i] = calloc(colums, sizeof(map[0][0]));
}
for (int i = 0; i <= k; i++) {
map[bytes[i][1]][bytes[i][0]] = 1;
}
uint32_t **costs = calloc(rows, sizeof(costs[0]));
for (int i = 0; i < rows; i++) {
costs[i] = calloc(colums, sizeof(costs[0][0]));
memset(costs[i], 255, colums * sizeof(costs[0][0]));
}
int (*queue)[2] = calloc(QUEUE_MAX, sizeof(queue[0]));
int queue_num = 1;
// Start at 0,0
queue[0][0] = 0;
queue[0][1] = 0;
costs[0][0] = 0;
int path_found = 0;
while (queue_num > 0) {
// Pop first
int x = queue[0][0];
int y = queue[0][1];
uint32_t cost = costs[x][y];
if (x == rows - 1 && y == colums - 1) {
path_found = 1;
break;
}
for (int i = 0; i < queue_num - 1; i++) {
queue[i][0] = queue[i+1][0];
queue[i][1] = queue[i+1][1];
}
queue_num--;
// Check each direction
for (int i = 0; i < directions_len; i++) {
int dx = directions[i][0];
int dy = directions[i][1];
int next_x = x + dx;
int next_y = y + dy;
// Outside of map, into wall, or better path exists
if (next_x < 0 || next_y < 0 || next_x >= rows || next_y >= colums || map[next_x][next_y] || costs[next_x][next_y] <= cost + 1) {
continue;
}
// Insert into queue
uint32_t next_cost = cost + 1;
costs[next_x][next_y] = next_cost;
int insert_idx;
for (insert_idx = 0; insert_idx < queue_num; insert_idx++) {
int qx = queue[insert_idx][0];
int qy = queue[insert_idx][1];
if (costs[qx][qy] > next_cost) {
break;
}
}
for (int j = queue_num; j > insert_idx; j--) {
queue[j][0] = queue[j-1][0];
queue[j][1] = queue[j-1][1];
}
queue[insert_idx][0] = next_x;
queue[insert_idx][1] = next_y;
queue_num++;
}
}
if (!path_found) {
printf("%i,%i\n", bytes[k][0], bytes[k][1]);
break;
}
for (int i = 0; i < rows; i++) {
free(map[i]);
free(costs[i]);
}
free(map);
free(costs);
}
free(bytes);
for (int i = 0; i < rows; i++) {
free(map[i]);
free(costs[i]);
}
free(map);
free(costs);
}