Skip to content

Commit 84da4fb

Browse files
committed
Solution 2025-08 (Playground)
1 parent 6c05cfe commit 84da4fb

File tree

5 files changed

+168
-0
lines changed

5 files changed

+168
-0
lines changed

src/main/kotlin/de/ronny_h/aoc/extensions/Combinations.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ fun <E> Iterable<E>.combinations() = sequence {
1616
}
1717
}
1818

19+
/**
20+
* @return All pairwise combinations of list elements without the reflexive and symmetrical ones.
21+
*/
22+
fun <E> List<E>.symmetricalCombinations() = sequence {
23+
forEachIndexed { i, a ->
24+
for (j in i + 1..lastIndex) {
25+
yield(a to get(j))
26+
}
27+
}
28+
}
29+
1930
/**
2031
* @return All pairwise combinations of list elements of the [first] and the [second] list.
2132
*/

src/main/kotlin/de/ronny_h/aoc/extensions/numbers/IntegralNumbers.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ fun Long.toIntChecked(): Int {
2626
return this.toInt()
2727
}
2828

29+
fun Long.squared() = this * this
30+
2931
/**
3032
* @return This Int to the power of [power].
3133
*/

src/main/kotlin/de/ronny_h/aoc/extensions/threedim/Vector.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package de.ronny_h.aoc.extensions.threedim
22

3+
import de.ronny_h.aoc.extensions.numbers.squared
34
import kotlin.math.abs
45
import kotlin.math.cbrt
6+
import kotlin.math.sqrt
57

68
data class Vector(val x: Long, val y: Long, val z: Long) {
79
companion object {
@@ -10,7 +12,11 @@ data class Vector(val x: Long, val y: Long, val z: Long) {
1012

1113
operator fun plus(other: Vector) = Vector(x + other.x, y + other.y, z + other.z)
1214
operator fun minus(other: Vector) = Vector(x - other.x, y - other.y, z - other.z)
15+
1316
infix fun taxiDistanceTo(other: Vector): Long = abs(other.x - x) + abs(other.y - y) + abs(other.z - z)
17+
infix fun straightLineDistanceTo(other: Vector): Double =
18+
sqrt((other.x - x).squared().toDouble() + (other.y - y).squared() + (other.z - z).squared())
19+
1420
fun abs(): Double = cbrt(x * x.toDouble() + y * y.toDouble() + z * z.toDouble())
1521
}
1622

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package de.ronny_h.aoc.year2025.day08
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.symmetricalCombinations
5+
import de.ronny_h.aoc.extensions.threedim.Vector
6+
import de.ronny_h.aoc.extensions.threedim.Vector.Companion.ZERO
7+
8+
fun main() = Playground().run(122430, 8135565324)
9+
10+
class Playground : AdventOfCode<Long>(2025, 8) {
11+
override fun part1(input: List<String>): Long = JunctionBoxConnector(input).connectShortest(1000)
12+
13+
override fun part2(input: List<String>): Long = JunctionBoxConnector(input).connectShortest()
14+
}
15+
16+
fun List<String>.parseJunctionBoxes() = map { it.split(",").map(String::toLong) }
17+
.map { (x, y, z) -> Vector(x, y, z) }
18+
19+
class JunctionBoxConnector(input: List<String>) {
20+
21+
private val boxes = input.parseJunctionBoxes()
22+
23+
fun connectShortest(n: Int? = null): Long {
24+
val distances = boxes.pairwiseDistances()
25+
.sortedBy { it.distance }
26+
.let { dist -> n?.let { dist.take(n) } ?: dist }
27+
val circuits = mutableListOf<MutableSet<Vector>>()
28+
29+
var lastMergingPair: Pair<Vector, Vector> = ZERO to ZERO
30+
31+
distances.forEach { (boxes, _) ->
32+
val containsFirst = circuits.find { it.contains(boxes.first) }
33+
val containsSecond = circuits.find { it.contains(boxes.second) }
34+
35+
when {
36+
containsFirst == null && containsSecond == null -> {
37+
circuits.add(mutableSetOf(boxes.first, boxes.second))
38+
}
39+
40+
containsFirst == containsSecond -> {
41+
// already in same circuit -> do nothing
42+
}
43+
44+
containsFirst != null && containsSecond != null -> {
45+
containsFirst.addAll(containsSecond)
46+
circuits.remove(containsSecond)
47+
lastMergingPair = boxes
48+
}
49+
50+
else -> {
51+
containsFirst?.add(boxes.second)
52+
containsSecond?.add(boxes.first)
53+
lastMergingPair = boxes
54+
}
55+
}
56+
}
57+
58+
return n?.let {
59+
circuits
60+
.map(MutableSet<Vector>::size)
61+
.sorted()
62+
.takeLast(3)
63+
.reduce(Int::times)
64+
.toLong()
65+
}
66+
?: (lastMergingPair.first.x * lastMergingPair.second.x)
67+
}
68+
}
69+
70+
fun List<Vector>.pairwiseDistances(): List<BoxDistance> = symmetricalCombinations().map { boxes ->
71+
val (a, b) = boxes
72+
BoxDistance(boxes, a straightLineDistanceTo b)
73+
}.toList()
74+
75+
data class BoxDistance(val boxes: Pair<Vector, Vector>, val distance: Double)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package de.ronny_h.aoc.year2025.day08
2+
3+
import de.ronny_h.aoc.extensions.asList
4+
import de.ronny_h.aoc.extensions.threedim.Vector
5+
import io.kotest.core.spec.style.StringSpec
6+
import io.kotest.matchers.shouldBe
7+
8+
class PlaygroundTest : StringSpec({
9+
10+
val input = """
11+
162,817,812
12+
57,618,57
13+
906,360,560
14+
592,479,940
15+
352,342,300
16+
466,668,158
17+
542,29,236
18+
431,825,988
19+
739,650,466
20+
52,470,668
21+
216,146,977
22+
819,987,18
23+
117,168,530
24+
805,96,715
25+
346,949,466
26+
970,615,88
27+
941,993,340
28+
862,61,35
29+
984,92,344
30+
425,690,689
31+
""".asList()
32+
33+
"input can be parsed" {
34+
"""
35+
162,817,812
36+
57,618,57
37+
906,360,560
38+
""".asList()
39+
.parseJunctionBoxes() shouldBe listOf(
40+
Vector(162, 817, 812),
41+
Vector(57, 618, 57),
42+
Vector(906, 360, 560),
43+
)
44+
}
45+
46+
"pairwiseDistances" {
47+
listOf(
48+
Vector(0, 0, 0),
49+
Vector(1, 0, 0),
50+
Vector(2, 0, 0),
51+
).pairwiseDistances() shouldBe listOf(
52+
BoxDistance(
53+
Vector(0, 0, 0) to
54+
Vector(1, 0, 0), 1.0
55+
),
56+
BoxDistance(
57+
Vector(0, 0, 0) to
58+
Vector(2, 0, 0), 2.0
59+
),
60+
BoxDistance(
61+
Vector(1, 0, 0) to
62+
Vector(2, 0, 0), 1.0
63+
),
64+
)
65+
}
66+
67+
"part 1" {
68+
JunctionBoxConnector(input).connectShortest(10) shouldBe 40
69+
}
70+
71+
"part 2" {
72+
Playground().part2(input) shouldBe 25272
73+
}
74+
})

0 commit comments

Comments
 (0)