advent2025

Advent of Code 2025 Solutions
git clone git://bsandro.tech/advent2025
Log | Files | Refs | README | LICENSE

day08.c (4980B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <inttypes.h>
      4 #include <math.h>
      5 #include <stdbool.h>
      6 #include <string.h>
      7 #include <strings.h>
      8 #include "cputime.h"
      9 
     10 typedef union {
     11     struct { int x, y, z; };
     12     int n[3];
     13 } Point;
     14 
     15 typedef struct {
     16     Point *p1;
     17     Point *p2;
     18     int d;
     19 } Distance;
     20 
     21 typedef struct {
     22     int id;
     23     Point *points[1000];
     24     int points_l;
     25 } Circuit;
     26 
     27 static int btoi(int bufl, int buf[bufl]) {
     28     int num = 0;
     29     for (int i=0;i<bufl;++i) num = num*10+buf[i];
     30     return num;
     31 }
     32 
     33 static int dist(Point p1, Point p2) {
     34     return sqrt(pow(p1.x-p2.x,2)+pow(p1.y-p2.y,2)+pow(p1.z-p2.z,2));
     35 }
     36 
     37 static int cmp_dist(const void *vd1, const void *vd2) {
     38     Distance *d1 = (Distance *)vd1;
     39     Distance *d2 = (Distance *)vd2;
     40     return d1->d - d2->d;
     41 }
     42 
     43 static bool has_point(Circuit *cir, const Point *p) {
     44     for (int i=0;i<cir->points_l;++i) {
     45         if (cir->points[i]==p) return true;
     46     }
     47     return false;
     48 }
     49 
     50 static void circuits_add(int *cirs_l, Circuit *cirs, Distance *dist) {
     51     for (int i=0;i<*cirs_l;++i) {
     52         Circuit *cir = &cirs[i];
     53         bool hit1 = has_point(cir, dist->p1);
     54         bool hit2 = has_point(cir, dist->p2);
     55         if (hit1&&hit2) { // both points are already in circuit
     56             return;
     57         } else if (hit1||hit2) { // only one of two points found
     58             cir->points[cir->points_l++] = hit1?dist->p2:dist->p1;
     59             return;
     60         }
     61     }
     62 
     63     int cir_id = (*cirs_l)++;
     64     Circuit *cir = &cirs[cir_id];
     65     cir->id = cir_id;
     66     cir->points[cir->points_l++] = dist->p1;
     67     cir->points[cir->points_l++] = dist->p2;
     68 }
     69 
     70 static bool circuits_overlap(Circuit *cir1, Circuit *cir2) {
     71     for (int i=0;i<cir1->points_l;++i) {
     72         if (has_point(cir2, cir1->points[i])) {
     73             return true;
     74         }
     75     }
     76     return false;
     77 }
     78 
     79 static void circuit_merge(Circuit *to, Circuit *from) {
     80     for (int i=0;i<from->points_l;++i) {
     81         if (!has_point(to, from->points[i])) {
     82             to->points[to->points_l++] = from->points[i];
     83         }
     84     }
     85     from->points_l = 0;
     86 }
     87 
     88 static int cmp_circuits(const void *vc1, const void *vc2) {
     89     const Circuit *c1 = (const Circuit *)vc1;
     90     const Circuit *c2 = (const Circuit *)vc2;
     91     return c2->points_l - c1->points_l;
     92 }
     93 
     94 static int circuits_merge(int circuits_l, Circuit *circuits) {
     95     int new_len = circuits_l;
     96     for (int i=0;i<circuits_l;++i) {
     97         for (int j=i;j<circuits_l;++j) {
     98             Circuit *cir1 = &circuits[i];
     99             Circuit *cir2 = &circuits[j];
    100             if (i==j) continue;
    101             if (cir1==cir2) continue;
    102             if (circuits_overlap(cir1, cir2)) {
    103                 circuit_merge(cir1, cir2);
    104                 new_len--;
    105                 break;
    106             }
    107         }
    108     }
    109     qsort(circuits, circuits_l, sizeof(Circuit), cmp_circuits);
    110     return new_len;
    111 }
    112 
    113 #define MAX_POINTS 1000
    114 
    115 int main(void) {
    116     uint64_t part1 = 0;
    117     uint64_t part2 = 0;
    118     Point *points = calloc(MAX_POINTS, sizeof(Point));
    119     int points_l = 0;
    120     int *n = points[0].n;
    121     int buf[16] = {0};
    122     int bufl = 0;
    123     for (int c=getchar();c!=EOF;c=getchar()) {
    124         if (c>='0'&&c<='9') buf[bufl++] = c-'0';
    125         else if (c==','||c=='\n') {
    126             *n = btoi(bufl, buf);
    127             bufl = 0;
    128             n++;
    129             if (c=='\n') n = points[++points_l].n;
    130         }
    131         if (points_l>MAX_POINTS) {
    132             printf("Too many input points, max: %d\n", MAX_POINTS);
    133             return 1;
    134         }
    135     }
    136     const int dists_cnt = (points_l*points_l-points_l)/2;
    137     const int conns_cnt = dists_cnt<1000 ? 10 : 1000;
    138     Distance *dists = calloc(dists_cnt, sizeof(Distance));
    139     int dists_l = 0;
    140     for (int i1=0;i1<points_l;++i1) {
    141         for (int i2=i1;i2<points_l;++i2) {
    142             if (i1==i2) continue;
    143             Point *p1 = &points[i1];
    144             Point *p2 = &points[i2];
    145             int d = dist(points[i1], points[i2]);
    146             dists[dists_l++] = (Distance){ p1, p2, d };
    147         }
    148     }
    149     qsort(dists, dists_l, sizeof(Distance), cmp_dist);
    150     Circuit *circuits = calloc(conns_cnt*2, sizeof(Circuit));
    151     int circuits_l = 0;
    152     for (int i=0;i<conns_cnt;++i) {
    153         circuits_add(&circuits_l, circuits, &dists[i]);
    154         circuits_l = circuits_merge(circuits_l, circuits);
    155     }
    156     qsort(circuits, circuits_l, sizeof(Circuit), cmp_circuits);
    157     part1 = circuits[0].points_l*circuits[1].points_l*circuits[2].points_l;
    158     free(circuits);
    159     // ---------------- p2 -------------------
    160     circuits = calloc(dists_l/2, sizeof(Circuit));
    161     circuits_l = 0;
    162     for (int i=0;i<dists_l;++i) {
    163         circuits_add(&circuits_l, circuits, &dists[i]);
    164         circuits_l = circuits_merge(circuits_l, circuits);
    165         if (circuits[0].points_l==points_l) {
    166             part2 = dists[i].p1->x * dists[i].p2->x;
    167             break;
    168         }
    169     }
    170     free(circuits);
    171     free(dists);
    172     free(points);
    173 
    174     printf("p1: %"PRIu64"\np2: %"PRIu64"\n", part1, part2);
    175     return 0;
    176 }