From fdfe0281d4d7bc916c85d6e8ea437400968743c6 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Fri, 14 Jul 2023 01:20:48 +0300 Subject: [PATCH] solve day 24 --- day24.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 1 + vec2.h | 5 + 3 files changed, 316 insertions(+) create mode 100644 day24.c diff --git a/day24.c b/day24.c new file mode 100644 index 0000000..3a3838f --- /dev/null +++ b/day24.c @@ -0,0 +1,310 @@ +#include +#include +#include + +#include "vec2.h" +#include "aoc.h" + +#define DAY24_QUEUE_CAPACITY (1024 * 256) + +typedef enum { + DIR24_UP, + DIR24_DOWN, + DIR24_LEFT, + DIR24_RIGHT, +} day24_direction; +char g_day24_direction[] = { + [DIR24_UP ] = '^', + [DIR24_DOWN ] = 'v', + [DIR24_LEFT ] = '<', + [DIR24_RIGHT] = '>' +}; + +typedef struct { + vec2 pos; + day24_direction direction; +} day24_blizzard; + +typedef struct { + day24_blizzard *blizzards; + u32 blizzard_count; + u32 width; + u32 height; +} day24_data; + +typedef struct { + i8 x[DAY24_QUEUE_CAPACITY]; + i8 y[DAY24_QUEUE_CAPACITY]; + u16 time[DAY24_QUEUE_CAPACITY]; + + i32 front; + i32 rear; +} day24_queue; + +static day24_direction day24_parse_direction(char symbol) +{ + switch(symbol) { + case '>': return DIR24_RIGHT; + case '<': return DIR24_LEFT; + case 'v': return DIR24_DOWN; + case '^': return DIR24_UP; + default: assert(false && "Invalid direction symbol"); + } +} + +static void* day24_parse(char** lines, int line_count) +{ + day24_data *data = malloc(sizeof(day24_data)); + data->width = strlen(lines[0]); + data->height = line_count; + data->blizzards = malloc(data->width * data->height * sizeof(day24_blizzard)); + data->blizzard_count = 0; + + for (int y = 1; y < data->height-1; y++) { + for (int x = 1; x < data->width-1; x++) { + char symbol = lines[y][x]; + if (symbol == '.') continue; + size_t blizzard_idx = data->blizzard_count; + + data->blizzards[blizzard_idx].pos.x = x; + data->blizzards[blizzard_idx].pos.y = y; + data->blizzards[blizzard_idx].direction = day24_parse_direction(symbol); + data->blizzard_count++; + } + } + + return data; +} + +static void day24_step(u16 *from_map, u16 *to_map, u32 width, u32 height, day24_blizzard *blizzards, u32 blizzard_count) +{ + memcpy(to_map, from_map, sizeof(u16) * width * height); + + for (int i = 0; i < blizzard_count; i++) { + day24_blizzard *blizz = &blizzards[i]; + vec2 *pos = &blizz->pos; + + to_map[pos->y * width + pos->x]--; + + if (blizz->direction == DIR24_UP) { + pos->y--; + if (pos->y == 0) { + pos->y = height-2; + } + } else if (blizz->direction == DIR24_DOWN) { + pos->y++; + if (pos->y == height-1) { + pos->y = 1; + } + } else if (blizz->direction == DIR24_LEFT) { + pos->x--; + if (pos->x == 0) { + pos->x = width-2; + } + } else { // if (blizz->direction == DIR24_RIGHT) { + pos->x++; + if (pos->x == width-1) { + pos->x = 1; + } + } + + to_map[pos->y * width + pos->x]++; + } +} + +static day24_blizzard *day24_get_blizzard_at(day24_blizzard *blizzards, u32 count, i32 x, i32 y) +{ + for (int i = 0; i < count; i++) { + if (blizzards[i].pos.x == x && blizzards[i].pos.y == y) { + return &blizzards[i]; + } + } + return NULL; +} + +static void day24_map_print(u16 *map, u32 width, u32 height) +{ + printf("#."); + for (int x = 2; x < width; x++) { + printf("#"); + } + printf("\n"); + + for (int y = 1; y < height-1; y++) { + printf("#"); + for (int x = 1; x < width-1; x++) { + u32 idx = y * width + x; + if (map[idx] == 0) { + printf("."); + } else { + printf("%d", map[idx]); + } + } + printf("#\n"); + } + + for (int x = 0; x < width-2; x++) { + printf("#"); + } + printf(".#\n"); +} + +static u32 day24_gcd(u32 a, u32 b) { + u32 R; + while ((a % b) != 0) { + R = a % b; + a = b; + b = R; + } + return b; +} + +static u32 day24_lcm(u32 a, u32 b) { + return a * b / day24_gcd(a, b); +} + +static void day24_generate_maps(u16 **maps, u32 count, day24_blizzard *blizzards, u32 blizzard_count, u32 width, u32 height) +{ + memset(maps[0], 0, width * height * sizeof(u16)); + for (int i = 0; i < blizzard_count; i++) { + vec2 *pos = &blizzards[i].pos; + u32 idx = pos->y * width + pos->x; + maps[0][idx]++; + } + + day24_blizzard moving_blizzards[blizzard_count]; + memcpy(moving_blizzards, blizzards, sizeof(day24_blizzard) * blizzard_count); + + for (int i = 1; i < count; i++) { + day24_step(maps[i-1], maps[i], width, height, moving_blizzards, blizzard_count); + } +} + +static void day24_queue_push(day24_queue *queue, i8 x, i8 y, u16 time) +{ + assert(queue->rear < DAY24_QUEUE_CAPACITY); + + if (queue->front == -1) { + queue->front = 0; + } + + queue->rear++; + queue->x[queue->rear] = x; + queue->y[queue->rear] = y; + queue->time[queue->rear] = time; +} + + +static void day24_queue_init(day24_queue *queue) +{ + queue->rear = -1; + queue->front = -1; +} + +static bool day24_queue_is_empty(day24_queue *queue) +{ + return queue->rear == -1; +} + +static void day24_queue_pop(day24_queue *queue, i8 *x, i8 *y, u16 *time) +{ + assert(!day24_queue_is_empty(queue)); + + *x = queue->x[queue->front]; + *y = queue->y[queue->front]; + *time = queue->time[queue->front]; + queue->front++; + if (queue->front > queue->rear) { + queue->front = -1; + queue->rear = -1; + } +} + +static bool day24_between(i8 value, i8 min, i8 max) +{ + return min <= value && value <= max; +} + +static u16 day24_bfs(u16 **maps, u32 map_count, u32 width, u32 height, vec2 *start, vec2 *goal, u32 start_time) +{ + u32 seen_size = 67108864; // 67108864 = 2^26 + bool *seen = calloc(seen_size, sizeof(bool)); + + day24_queue queue; + day24_queue_init(&queue); + day24_queue_push(&queue, start->x, start->y, start_time); + + while (!day24_queue_is_empty(&queue)) { + i8 x, y; + u16 time; + day24_queue_pop(&queue, &x, &y, &time); + + time++; + + u32 map_idx = time % map_count; + u16 *map = maps[map_idx]; + + vec2 offsets[] = { VEC2(1, 0), VEC2(-1, 0), VEC2(0, 1), VEC2(0, -1), VEC2(0, 0) }; + for (int i = 0; i < ARRAY_LEN(offsets); i++) { + i8 new_x = x + offsets[i].x; + i8 new_y = y + offsets[i].y; + + if (vec2_eq(goal, new_x, new_y)) { + return time; + } + + bool is_in_bounds = day24_between(new_x, 1, width-2) && day24_between(new_y, 1, height-2); + if (!is_in_bounds && !vec2_eq(start, new_x, new_y)) continue; + + u32 tile_idx = new_y * width + new_x; + if (map[tile_idx] > 0) continue; + + u32 seen_key = (map_idx << 16) | (new_x << 8) | (new_y); + assert(seen_key < seen_size); + if (seen[seen_key]) continue; + seen[seen_key] = true; + + day24_queue_push(&queue, new_x, new_y, time); + } + } + + return 0; +} + +static void day24_part1(void *p) +{ + day24_data *data = (day24_data*)p; + + u32 maps_count = day24_lcm(data->width-2, data->height-2); + u16 *maps[maps_count]; + for (int i = 0; i < maps_count; i++) { + maps[i] = malloc(data->width * data->height * sizeof(u16)); + } + day24_generate_maps(maps, maps_count, data->blizzards, data->blizzard_count, data->width, data->height); + + vec2 start = { 1, 0 }; + vec2 goal = { data->width-2, data->height-1 }; + printf("%d\n", day24_bfs(maps, maps_count, data->width, data->height, &start, &goal, 0)); +} + +static void day24_part2(void *p) +{ + day24_data *data = (day24_data*)p; + + u32 maps_count = day24_lcm(data->width-2, data->height-2); + u16 *maps[maps_count]; + for (int i = 0; i < maps_count; i++) { + maps[i] = malloc(data->width * data->height * sizeof(u16)); + } + day24_generate_maps(maps, maps_count, data->blizzards, data->blizzard_count, data->width, data->height); + + vec2 start = { 1, 0 }; + vec2 goal = { data->width-2, data->height-1 }; + + u32 time1 = day24_bfs(maps, maps_count, data->width, data->height, &start, &goal , 0); + u32 time2 = day24_bfs(maps, maps_count, data->width, data->height, &goal , &start, time1); + u32 time3 = day24_bfs(maps, maps_count, data->width, data->height, &start, &goal , time2); + printf("%d\n", time3); +} + +ADD_SOLUTION(24, day24_parse, day24_part1, day24_part2); diff --git a/main.c b/main.c index b976666..024632b 100644 --- a/main.c +++ b/main.c @@ -32,6 +32,7 @@ #include "day21.c" #include "day22.c" #include "day23.c" +#include "day24.c" Solution *find_solution(int day) { diff --git a/vec2.h b/vec2.h index e9308a2..7fdb0b1 100644 --- a/vec2.h +++ b/vec2.h @@ -1,6 +1,7 @@ #ifndef VEC2_H_ #define VEC2_H_ +#include #include "types.h" typedef struct { @@ -14,4 +15,8 @@ typedef struct { TYPEDEF_VEC2(u8); TYPEDEF_VEC2(u32); +static bool vec2_eq(vec2 *A, i32 x, i32 y) { + return A->x == x && A->y == y; +} + #endif //VEC2_H_