182 lines
4.7 KiB
C
182 lines
4.7 KiB
C
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
|
|
#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);
|