1+ import org.jetbrains.annotations.VisibleForTesting
2+ import kotlin.io.path.readLines
3+ import kotlin.math.pow
4+
5+ class Day08 : Day {
6+ override fun partOne (filename : String , verbose : Boolean ): Int =
7+ connectBoxes(filename, verbose, 1_000 )
8+
9+ override fun partTwo (filename : String , verbose : Boolean ): Int =
10+ connectBoxes(filename, verbose, null )
11+
12+ @VisibleForTesting
13+ internal fun connectBoxes (filename : String , verbose : Boolean , maxIterations : Int? ): Int {
14+ val points = filename.asPath().readLines().map {
15+ val (x, y, z) = it.split(" ," )
16+ Coordinate3d (x.toInt(), y.toInt(), z.toInt())
17+ }
18+ val parents = points.associateByTo(mutableMapOf ()) { it }
19+ val sizes = points.associateWithTo(mutableMapOf ()) { 1 }
20+
21+ fun union (a : Coordinate3d , b : Coordinate3d ) {
22+ var a = parents.findUltimateParent(a)
23+ var b = parents.findUltimateParent(b)
24+
25+ if (a == b) {
26+ return
27+ }
28+ if (sizes[a]!! > sizes[b]!! ) {
29+ val c = a
30+ a = b
31+ b = c
32+ }
33+ parents[a] = b
34+ sizes.computeIfPresent(b) { _, previous -> previous + sizes[a]!! }
35+ sizes[a] = 0
36+ }
37+
38+ val order = points.flatMapIndexed { index, i ->
39+ points.drop(index + 1 ).map { j ->
40+ Triple (squareDistance(i, j), i, j)
41+ }
42+ }.sortedBy { (distance) -> distance }
43+
44+ if (maxIterations != null ) {
45+ order.take(maxIterations).forEach { (_, i, j) ->
46+ union(i, j)
47+ }
48+ val descendingSizes = sizes.values.sortedDescending()
49+ return descendingSizes.take(3 ).reduce(Int ::times)
50+ } else {
51+ order.forEach { (_, i, j) ->
52+ union(i, j)
53+
54+ if (sizes[parents.findUltimateParent(i)] == points.size) {
55+ return i.x * j.x
56+ }
57+ }
58+ throw IllegalStateException (" Cannot resolve" )
59+ }
60+ }
61+
62+ companion object : Day .Main (" Day08.txt" ) {
63+ @JvmStatic
64+ fun main (args : Array <String >) = main()
65+ }
66+
67+ private fun squareDistance (p1 : Coordinate3d , p2 : Coordinate3d ) =
68+ (p2.x - p1.x).toLong().pow(2 ) + (p2.y - p1.y).toLong().pow(2 ) + (p2.z - p1.z).toLong().pow(2 )
69+
70+ private fun MutableMap <Coordinate3d , Coordinate3d >.findUltimateParent (coordinate3d : Coordinate3d ): Coordinate3d {
71+ if (coordinate3d != get(coordinate3d)) {
72+ put(coordinate3d, findUltimateParent(get(coordinate3d)!! ))
73+ }
74+ return get(coordinate3d)!!
75+ }
76+
77+ private fun Long.pow (n : Int ) =
78+ toDouble().pow(n).toLong()
79+ }
0 commit comments