advent-of-code-2024/day-18/main.c

160 lines
4.1 KiB
C

#include "aoc.h"
typedef struct {
i32 x, y;
} Vec2i;
static Vec2i
parse_vec2i(str line, Arena tmp) {
str left, right;
str_split(line, STR(","), &left, &right);
Vec2i result = {
.x = parse_i64(str_trim(left), tmp),
.y = parse_i64(str_trim(right), tmp),
};
return result;
}
static Vec2i
vec2i(i32 x, i32 y) {
Vec2i result = { .x = x, .y = y };
return result;
}
static void
simulate_falling(Vec2i *bytes, isize bytes_len, u8 *grid, i32 width, i32 height) {
for (isize i = 0; i < bytes_len; i++) {
Vec2i byte = bytes[i];
grid[byte.y * width + byte.x] = 1;
}
}
static void
dump_grid(u8 *grid, i32 width, i32 height) {
for (i32 y = 0; y < height; y++) {
for (i32 x = 0; x < width; x++) {
u8 cell = grid[y * width + x];
if (cell) {
printf("#");
} else {
printf(".");
}
}
printf("\n");
}
}
typedef struct {
Vec2i *points;
i32 write, read;
isize size;
} Queue;
static inline i32
queue_next(Queue *queue, i32 index) {
return (index + 1) % queue->size;
}
static inline void
queue_push(Queue *queue, Vec2i pos) {
ASSERT(queue_next(queue, queue->write) != queue->read);
queue->points[queue->write] = pos;
queue->write = queue_next(queue, queue->write);
}
static inline Vec2i
queue_pop(Queue *queue) {
ASSERT(queue->read != queue->write);
Vec2i result = queue->points[queue->read];
queue->read = queue_next(queue, queue->read);
return result;
}
static inline bool
queue_empty(Queue *queue) {
return queue->write == queue->read;
}
static i32
solve(Arena temp, u8 *grid, i32 width, i32 height) {
i32 end_x = width - 1, end_y = height - 1;
i32 x = 0, y = 0;
Queue queue = { .size = 1024 };
queue.points = ARENA_ALLOC_ARRAY(&temp, Vec2i, queue.size);
i32 *distance = ARENA_ALLOC_ARRAY(&temp, i32, width * height);
for (i32 i = 0; i < width * height; i++) {
distance[i] = INT32_MAX;
}
distance[y * width + x] = 0;
queue_push(&queue, vec2i(x, y));
static const Vec2i offsets[] = {
{ .x = 0, .y = -1 },
{ .x = 0, .y = 1 },
{ .x = -1, .y = 0 },
{ .x = 1, .y = 0 },
};
while (!queue_empty(&queue)) {
Vec2i point = queue_pop(&queue);
i32 dist = distance[point.y * width + point.x];
ASSERT(dist < INT32_MAX);
for (i32 i = 0; i < 4; i++) {
Vec2i offset = offsets[i];
i32 nx = point.x + offset.x;
i32 ny = point.y + offset.y;
if (nx >= 0 && ny >= 0 && nx < width && ny < height
&& !grid[ny * width + nx]
&& dist + 1 < distance[ny * width + nx])
{
distance[ny * width + nx] = dist + 1;
queue_push(&queue, vec2i(nx, ny));
}
}
}
return distance[end_y * width + end_x];
}
int main(int argc, char **argv) {
Arena *arena = make_arena(Megabytes(1));
Tokens lines = read_lines(arena, argv[1]);
Vec2i *bytes = ARENA_ALLOC_ARRAY(arena, Vec2i, lines.len);
bool is_test = true;
for (isize i = 0; i < lines.len; i++) {
bytes[i] = parse_vec2i(lines.tokens[i], *arena);
if (bytes[i].x > 6 || bytes[i].y > 6) {
is_test = false;
}
}
i32 width, height;
i32 part_1_limit;
if (is_test) {
width = 7;
height = 7;
part_1_limit = 12;
}
else {
width = 71;
height = 71;
part_1_limit = 1024;
}
u8 *grid = ARENA_ALLOC_ARRAY(arena, u8, width * height);
// part 1
simulate_falling(bytes, part_1_limit, grid, width, height);
/* dump_grid(grid, width, height); */
i32 part_1 = solve(*arena, grid, width, height);
printf("%d\n", part_1);
// part 2
memset(grid, 0, width * height);
for (isize cutoff = 0; cutoff < lines.len; cutoff++) {
simulate_falling(bytes + cutoff, 1, grid, width, height);
i32 result = solve(*arena, grid, width, height);
if (result == INT32_MAX) {
printf("%d,%d\n", bytes[cutoff].x, bytes[cutoff].y);
break;
}
}
}