That's interesting. I found part 1 to be the hard part and part 2 was just simplifying part 1. They ran in about the same time for me, too.
Part 1 run time:
Input IO: 0m 0s 10ms
Input Parse: 0m 0s 21ms
Algorithm: 0m 0s 250ms
Total: 0m 0s 281ms
Part 2 run time:
Input IO: 0m 0s 11ms
Input Parse: 0m 0s 22ms
Algorithm: 0m 0s 255ms
Total: 0m 0s 288ms
Code:
const val connectionsLimit = 1000
const val circuitsLimit = 3
fun part1() {
val input = getInput(8)
val circuits: MutableList<MutableSet<Triple<Int, Int, Int>>> = parseInput1(input)
val distances: MutableList<Pair<Pair<Triple<Int, Int, Int>, Triple<Int, Int, Int>>, Double>> = mutableListOf()
val tempList = circuits.toList()
for (i in tempList.indices) {
val left = tempList[i].first()
for (j in i + 1..<tempList.size) {
val right = tempList[j].first()
val distance = calculateDistance(left, right)
val coordinates = left to right
distances.add(coordinates to distance)
}
}
distances.sortBy { it.second }
// Parts 1 and 2 are the same until here
for (i in 0..<connectionsLimit) {
val distance = distances[i]
val leftCircuit = circuits.first { it.contains(distance.first.first) }
val rightCircuit = circuits.first { it.contains(distance.first.second) }
if (leftCircuit != rightCircuit) {
leftCircuit.addAll(rightCircuit)
circuits.remove(rightCircuit)
}
}
val sizes = circuits.map { it.size.toLong() }.sortedDescending().slice(0..<circuitsLimit)
val total = sizes.reduce { acc, i -> acc * i }
println(total)
}
fun part2() {
val input = getInput(8)
val circuits: MutableList<MutableSet<Triple<Int, Int, Int>>> = parseInput1(input)
val distances: MutableList<Pair<Pair<Triple<Int, Int, Int>, Triple<Int, Int, Int>>, Double>> = mutableListOf()
val tempList = circuits.toList()
for (i in tempList.indices) {
val left = tempList[i].first()
for (j in i + 1..<tempList.size) {
val right = tempList[j].first()
val distance = calculateDistance(left, right)
val coordinates = left to right
distances.add(coordinates to distance)
}
}
distances.sortBy { it.second }
// Part 2 differs starting here
var answer = 0
for (distance in distances) {
val leftCircuit = circuits.first { it.contains(distance.first.first) }
val rightCircuit = circuits.first { it.contains(distance.first.second) }
if (leftCircuit != rightCircuit) {
leftCircuit.addAll(rightCircuit)
circuits.remove(rightCircuit)
if (circuits.size == 1) {
answer = distance.first.first.first * distance.first.second.first
break
}
}
}
println(answer)
}
fun parseInput1(input: String): MutableList<MutableSet<Triple<Int, Int, Int>>> {
return input.lines()
.filter { it.isNotBlank() }
.map {
val split = it.split(",")
mutableSetOf(Triple(split[0].toInt(), split[1].toInt(), split[2].toInt()))
}
.toMutableList()
}
fun calculateDistance(left: Triple<Int, Int, Int>, right: Triple<Int, Int, Int>): Double {
val dx = (left.first - right.first).toDouble()
val dy = (left.second - right.second).toDouble()
val dz = (left.third - right.third).toDouble()
val distanceSquared = dx.pow(2) + dy.pow(2) + dz.pow(2)
return sqrt(distanceSquared)
}