#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; } } }