#include #include #include #include #define BUFFER_SIZE 128 #define MAX_SENSORS 128 #define MAX_RANGES 128 #define Y_ROW 2000000L #define MIN_YPOS 0L #define MAX_YPOS 4000000L #define XTUNING 4000000ULL #define max(a,b) (a >= b ? a : b) #define min(a,b) (a <= b ? a : b) #define abs(v) ((v) < 0 ? (-1) * (v) : (v)) typedef struct sensor { long x; long y; long beaconX; long beaconY; long radius; } SENSOR; long dist(long, long, long, long); int exists(long [], int, long); unsigned overlap(long, long, long, long); int main() { char buf[BUFFER_SIZE], *p, c; memset(buf, 0, BUFFER_SIZE); p = buf; SENSOR sensors[MAX_SENSORS], tmp; int sensor_count = 0; while ((c = getchar()) != EOF) { *p++ = c; if (c == '\n') { sscanf(buf, "Sensor at x=%li, y=%li: closest beacon is at x=%li, y=%li", &tmp.x, &tmp.y, &tmp.beaconX, &tmp.beaconY); tmp.radius = dist(tmp.x, tmp.y, tmp.beaconX, tmp.beaconY); sensors[sensor_count] = tmp; sensor_count++; memset(buf, 0, BUFFER_SIZE); p = buf; } } // Scan every row in the given territory for (long jk = MIN_YPOS; jk < MAX_YPOS; jk++) { // Save the range for each sensor long (*scanned)[2]; scanned = (long(*)[2])malloc(sensor_count * sizeof(long[2])); memset(scanned, 0, sensor_count * sizeof(long[2])); unsigned sum = 0; // Find all scanned in y=jk for (int i = 0; i < sensor_count; i++) { // Not in range if (abs(sensors[i].y - jk) > sensors[i].radius) { continue; } unsigned tmp = (sensors[i].radius - abs(sensors[i].y - jk)); scanned[i][0] = sensors[i].x - tmp; scanned[i][1] = sensors[i].x + tmp; } long (*ranges)[2]; ranges = (long(*)[2])malloc(MAX_RANGES * sizeof(long[2])); memset(ranges, 0, MAX_RANGES * sizeof(long[2])); int range_count = 0; // Count scanned and remove overlaps for (int i = 0; i < sensor_count; i++) { long sections[16][2]; int section_count = 0; sections[0][0] = scanned[i][0]; sections[0][1] = scanned[i][1]; section_count++; for (int j = 0; j < range_count; j++) { for (int k = 0; k < section_count; k++) { // Not overlapping if (sections[k][0] > ranges[j][1] || sections[k][1] < ranges[j][0]) { continue; } // fully covered else if (sections[k][0] >= ranges[j][0] && sections[k][1] <= ranges[j][1]) { for (int l = k; l < section_count - 1; l++) { sections[l][0] = sections[l+1][0]; sections[l][1] = sections[l+1][1]; } section_count--; break; } // Inverse covered splits section to two else if (sections[k][0] < ranges[j][0] && sections[k][1] > ranges[j][1]) { // Push everything forward for (int l = section_count; l > k + 1; l--) { sections[l][0] = sections[l-1][0]; sections[l][1] = sections[l-1][1]; } section_count++; sections[k+1][1] = sections[k][1]; sections[k][1] = ranges[j][0] - 1; sections[k+1][0] = ranges[j][1] + 1; } // Left hook else if (sections[k][0] < ranges[j][0] && sections[k][1] <= ranges[j][1]) { sections[k][1] = ranges[j][0] - 1; } // Right hook else if (sections[k][0] >= ranges[j][0] && sections[k][1] > ranges[j][1]) { sections[k][0] = ranges[j][1] + 1; } } } for (int j = 0; j < section_count; j++) { ranges[range_count][0] = sections[j][0]; ranges[range_count][1] = sections[j][1]; range_count++; } } //printf("OPOPOP\n"); int changeCount = 0; // Combine ranges do { changeCount = 0; for (int i = 0; i < range_count; i++) { for (int j = i + 1; j < range_count; j++) { if (ranges[i][0] == ranges[j][1] + 1) { ranges[i][0] = ranges[j][0]; for (int k = j; k < range_count - 1; k++) { ranges[k][0] = ranges[k+1][0]; ranges[k][1] = ranges[k+1][1]; } range_count--; changeCount++; } else if (ranges[i][1] + 1 == ranges[j][0]) { ranges[i][1] = ranges[j][1]; for (int k = j; k < range_count - 1; k++) { ranges[k][0] = ranges[k+1][0]; ranges[k][1] = ranges[k+1][1]; } range_count--; changeCount++; } } } } while (changeCount != 0); for (int i = 0; i < range_count; i++) { //printf("[%li,%li]\n", ranges[i][0], ranges[i][1]); sum += ranges[i][1] - ranges[i][0] + 1; } // I don't really understand why, but we also have to exclude beacons long beaconInWay[32]; int beaconInWayCount = 0; for (int i = 0; i < sensor_count; i++) { int skip = 0; if (sensors[i].beaconY != jk) { continue; } for (int k = 0; k < beaconInWayCount; k++) { if (beaconInWay[k] == sensors[i].beaconX) { skip = 1; break; } } if (skip) { continue; } for (int j = 0; j < range_count; j++) { if (sensors[i].beaconX >= ranges[j][0] && sensors[i].beaconX <= ranges[j][1]) { beaconInWay[beaconInWayCount] = sensors[i].beaconX; beaconInWayCount++; sum -= 1; } } } // Finally print the results if (jk == Y_ROW) { printf("Part one: %u\n", sum); } // Second part for (int i = 0; i < range_count; i++) { if (ranges[i][0] > MIN_YPOS && ranges[i][0] <= MAX_YPOS) { printf("X: %li, Y: %li\n", ranges[i][0] - 1, jk); printf("Second part: %llu\n", (unsigned long long)(ranges[i][0]-1)*XTUNING+(unsigned long long)jk); } } free(scanned); free(ranges); } } long dist(long x1, long y1, long x2, long y2) { return abs(x1-x2) + abs(y1-y2); } // We could do better if we want speed // But I hope it is enough int exists(long scanned[], int scanned_count, long x) { for (int i = 0; i < scanned_count; i++) { if (scanned[i] == x) { return 1; } } return 0; } unsigned overlap(long min1, long max1, long min2, long max2) { if (max1 < min2 || max2 < min1) return 0; return min(max1, max2) - max(min1, min2) + 1; }