1+ import path from "node:path" ;
2+ import { readInputLineByLine } from "@utils/io" ;
3+ import { Coord3d } from "@utils/grid3d" ;
4+
5+ export async function part1 ( inputFile : string , isTestInput : boolean = false ) {
6+ return await day8 ( inputFile , findCircuits , isTestInput ) ;
7+ }
8+
9+ export async function part2 ( inputFile : string , isTestInput : boolean = false ) {
10+ return await day8 ( inputFile , findCircuits , isTestInput ) ;
11+ }
12+
13+ async function day8 ( inputFile : string , calcFn ?: ( boxes : Coord3d [ ] , isTestInput : boolean ) => number , isTestInput : boolean = false ) {
14+ const inputPath = path . join ( __dirname , inputFile ) ;
15+ const lines = await readInputLineByLine ( inputPath ) ;
16+ const boxes = lines . map ( ( line ) => {
17+ const split = line . split ( "," ) . map ( Number ) ;
18+ return new Coord3d ( split [ 0 ] , split [ 1 ] , split [ 2 ] ) ;
19+ } ) ;
20+ return calcFn ?.( boxes , isTestInput ) ;
21+ }
22+
23+ function dist ( a : Coord3d , b : Coord3d ) : number {
24+ return Math . sqrt ( ( a . x - b . x ) ** 2 + ( a . y - b . y ) ** 2 + ( a . z - b . z ) ** 2 ) ;
25+ }
26+
27+ function findCircuits ( boxes : Coord3d [ ] , isTestInput : boolean ) : number {
28+ const n = boxes . length ;
29+ const k = isTestInput ? Math . floor ( n / 2 ) : n ;
30+
31+ // Collect all pairs sorted by distance
32+ const pairs : [ number , number , number ] [ ] = [ ] ;
33+ for ( let i = 0 ; i < n ; i ++ ) {
34+ for ( let j = i + 1 ; j < n ; j ++ ) {
35+ pairs . push ( [ dist ( boxes [ i ] , boxes [ j ] ) , i , j ] ) ;
36+ }
37+ }
38+ pairs . sort ( ( a , b ) => a [ 0 ] - b [ 0 ] ) ;
39+
40+ // Union-Find
41+ const parent = Array . from ( { length : n } , ( _ , i ) => i ) ;
42+ const size = new Array ( n ) . fill ( 1 ) ;
43+
44+ function find ( x : number ) : number {
45+ while ( parent [ x ] !== x ) {
46+ parent [ x ] = parent [ parent [ x ] ] ;
47+ x = parent [ x ] ;
48+ }
49+ return x ;
50+ }
51+
52+ function union ( a : number , b : number ) {
53+ a = find ( a ) ; b = find ( b ) ;
54+ if ( a === b ) return ;
55+ if ( size [ a ] < size [ b ] ) [ a , b ] = [ b , a ] ;
56+ parent [ b ] = a ;
57+ size [ a ] += size [ b ] ;
58+ }
59+
60+ for ( let i = 0 ; i < k ; i ++ ) {
61+ union ( pairs [ i ] [ 1 ] , pairs [ i ] [ 2 ] ) ;
62+ }
63+
64+ // Collect circuit sizes via root nodes
65+ const sizes : number [ ] = [ ] ;
66+ for ( let i = 0 ; i < n ; i ++ ) {
67+ if ( find ( i ) === i ) sizes . push ( size [ i ] ) ;
68+ }
69+ sizes . sort ( ( a , b ) => b - a ) ;
70+
71+ return sizes [ 0 ] * sizes [ 1 ] * sizes [ 2 ] ;
72+ }
0 commit comments