diff --git a/day15.c b/day15.c new file mode 100644 index 0000000..ccf6017 --- /dev/null +++ b/day15.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include + +#include "aoc.h" +#include "vec2.h" + +typedef struct { + vec2 sensor; + vec2 beacon; +} day15_reading; + +typedef struct { + day15_reading *readings; + size_t count; +} day15_readings; + +static vec2 day15_parse_point(char *line) +{ + vec2 point; + point.x = strtol(strstr(line, "x=")+2, NULL, 10); + point.y = strtol(strstr(line, "y=")+2, NULL, 10); + return point; +} + +static void *day15_parse(char **lines, int line_count) +{ + day15_readings *readings = malloc(sizeof(day15_readings)); + readings->readings = malloc(line_count * sizeof(day15_reading)); + readings->count = line_count; + + for (size_t i = 0; i < line_count; i++) { + day15_reading *r = &readings->readings[i]; + r->sensor = day15_parse_point(lines[i]); + r->beacon = day15_parse_point(strchr(lines[i], ':')); + } + + return readings; +} + +static u32 manhattan_dist(vec2 *A, vec2 *B) +{ + return abs(A->x - B->x) + abs(A->y - B->y); +} + +static void print_reading(day15_reading *r) +{ + printf("Sensor{%d,%d}, Beacon{%d,%d}\n", r->sensor.x, r->sensor.y, r->beacon.x, r->beacon.y); +} + +static void day15_get_bounds( + day15_reading *readings, size_t readings_count, + i32 target_row, + i32 *left_bounds, i32 *right_bounds, + size_t *bounds_count + ) +{ + for (size_t i = 0; i < readings_count; i++) { + day15_reading *r = &readings[i]; + + u32 range = manhattan_dist(&r->beacon, &r->sensor); + u32 dist_to_target = abs(target_row - r->sensor.y); + if (dist_to_target <= range) { + u32 margin = range - dist_to_target; + + left_bounds[*bounds_count] = r->sensor.x - margin; + right_bounds[*bounds_count] = r->sensor.x + margin; + + (*bounds_count)++; + } + } +} + +static void swap_i32(i32 *A, i32 *B) +{ + i32 C = *A; + *A = *B; + *B = C; +} + +static void day15_sort_bounds(i32 *left_bounds, i32 *right_bounds, size_t bounds_count) +{ + if (bounds_count <= 1) return; + + for (int i = 0; i < bounds_count - 1; i++) { + for (int j = i+1; j < bounds_count; j++) { + if (left_bounds[i] > left_bounds[j]) { + swap_i32(&left_bounds[i], &left_bounds[j]); + swap_i32(&right_bounds[i], &right_bounds[j]); + } + } + } +} + +static void day15_remove_bound(i32 *left_bounds, i32 *right_bounds, size_t *bounds_count, int k) +{ + for (size_t i = k; i < *bounds_count - 1; i++) { + left_bounds[i] = left_bounds[i+1]; + right_bounds[i] = right_bounds[i+1]; + } + (*bounds_count)--; +} + +static void day15_merge_bounds(i32 *left_bounds, i32 *right_bounds, size_t *bounds_count) +{ + if (*bounds_count <= 1) return; + + for (size_t i = 0; i < *bounds_count-1; i++) { + if (right_bounds[i] >= left_bounds[i+1] && right_bounds[i] >= right_bounds[i+1]) { + day15_remove_bound(right_bounds, left_bounds, bounds_count, i+1); + i--; + } else if (right_bounds[i] >= left_bounds[i+1]) { + right_bounds[i] = right_bounds[i+1]; + day15_remove_bound(right_bounds, left_bounds, bounds_count, i+1); + i--; + } + } +} + +static bool is_vec2_in_bounds(vec2 *point, i32 y, i32 min_x, i32 max_x) +{ + return point->y == y && (min_x <= point->x && point->x <= max_x); +} + +static u32 day15_get_findings_count_in_bounds(day15_reading *readings, size_t reading_count, i32 y, i32 min_x, i32 max_x) +{ + u32 count = 0; + for (int i = 0; i < reading_count; i++) { + if (is_vec2_in_bounds(&readings->sensor, y, min_x, max_x) || is_vec2_in_bounds(&readings->beacon, y, min_x, max_x)) { + count++; + } + } + return count; +} + +static void day15_part1(void *p) +{ + day15_readings *data = (day15_readings*)p; + + i32 target_row = 2000000; + + i32 *left_bounds = malloc(sizeof(i32) * data->count); + i32 *right_bounds = malloc(sizeof(i32) * data->count); + size_t bounds_count = 0; + + day15_get_bounds(data->readings, data->count, target_row, left_bounds, right_bounds, &bounds_count); + day15_sort_bounds(left_bounds, right_bounds, bounds_count); + day15_merge_bounds(left_bounds, right_bounds, &bounds_count); + + u32 answer = 0; + for (size_t i = 0; i < bounds_count; i++) { + answer += abs(right_bounds[i] - left_bounds[i]); + answer -= day15_get_findings_count_in_bounds(data->readings, data->count, target_row, left_bounds[i], right_bounds[i]); + } + + printf("%d\n", answer); +} + +static void day15_part2(void *p) +{ + day15_readings *data = (day15_readings*)p; + + i32 *left_bounds = malloc(sizeof(i32) * data->count); + i32 *right_bounds = malloc(sizeof(i32) * data->count); + + for (i32 y = 0; y < 4000000; y++) { + size_t bounds_count = 0; + + day15_get_bounds(data->readings, data->count, y, left_bounds, right_bounds, &bounds_count); + day15_sort_bounds(left_bounds, right_bounds, bounds_count); + day15_merge_bounds(left_bounds, right_bounds, &bounds_count); + if (bounds_count > 1) { + i32 x = right_bounds[0] + 1; + printf("%lu\n", (u64)x * 4000000 + (u64)y); + break; + } + } +} + +ADD_SOLUTION(15, day15_parse, day15_part1, day15_part2); diff --git a/main.c b/main.c index 976938e..a5c4f79 100644 --- a/main.c +++ b/main.c @@ -23,6 +23,7 @@ #include "day12.c" #include "day13.c" #include "day14.c" +#include "day15.c" Solution *find_solution(int day) { diff --git a/types.h b/types.h index fd4c64c..07a1266 100644 --- a/types.h +++ b/types.h @@ -8,9 +8,11 @@ typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; +typedef uint64_t u64; typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; +typedef int64_t i64; #endif //TYPES_H_ diff --git a/vec2.h b/vec2.h index 6ff7f71..30030f0 100644 --- a/vec2.h +++ b/vec2.h @@ -4,7 +4,7 @@ #include "types.h" typedef struct { - int x, y; + i32 x, y; } vec2; #define TYPEDEF_VEC2(type) typedef struct { type x, y; } vec2_##type