@@ -4,6 +4,8 @@ import eu.sim642.adventofcodelib.IteratorImplicits.*
44import eu .sim642 .adventofcodelib .graph .Kruskal
55import eu .sim642 .adventofcodelib .pos .Pos3
66
7+ import scala .collection .mutable
8+
79object Day8 {
810
911 extension (pos : Pos3 ) {
@@ -13,20 +15,28 @@ object Day8 {
1315 }
1416 }
1517
16- def closestPairsSeq (junctionBoxes : Seq [Pos3 ]): Seq [(Pos3 , Pos3 )] = {
17- // noinspection ConvertibleToMethodValue
18- (for {
18+ extension [A ](queue : mutable.PriorityQueue [A ]) {
19+ // normal queue.iterator does not yield dequeue order
20+ def dequeueIterator : Iterator [A ] = new Iterator [A ] {
21+ override def hasNext : Boolean = queue.nonEmpty
22+
23+ override def next (): A = queue.dequeue()
24+ }
25+ }
26+
27+ def iterateClosestPairs (junctionBoxes : Seq [Pos3 ]): Iterator [(Pos3 , Pos3 )] = {
28+ // it is faster to use a PriorityQueue than sort the Seq of all pairs because Kruskal will only need some closest pairs, not all
29+ val queue = mutable.PriorityQueue .empty[((Pos3 , Pos3 ), Long )](using Ordering .by(- _._2))
30+ for {
1931 // faster than combinations(2)
2032 (p1, i) <- junctionBoxes.iterator.zipWithIndex
2133 p2 <- junctionBoxes.view.slice(i + 1 , junctionBoxes.size).iterator
22- } yield (p1, p2) -> (p1 euclideanDistanceSqr p2)) // no need to sqrt distance just for sorting
23- .toSeq
24- .sortBy(_._2)
25- .map(_._1)
34+ } queue.enqueue((p1, p2) -> (p1 euclideanDistanceSqr p2)) // no need to sqrt distance just for sorting
35+ queue.dequeueIterator.map(_._1)
2636 }
2737
2838 def multiplySizesAfter (junctionBoxes : Seq [Pos3 ], after : Int = 1000 , sizes : Int = 3 ): Int = {
29- val closestPairs = closestPairsSeq (junctionBoxes)
39+ val closestPairs = iterateClosestPairs (junctionBoxes)
3040 val (ufAfter, _) = Kruskal .iterate(junctionBoxes, closestPairs)(after)
3141
3242 ufAfter.groups()
@@ -38,7 +48,7 @@ object Day8 {
3848
3949 // TODO: deduplicate
4050 def multiplyLastXs (junctionBoxes : Seq [Pos3 ]): Int = {
41- val closestPairs = closestPairsSeq (junctionBoxes)
51+ val closestPairs = iterateClosestPairs (junctionBoxes)
4252 val lastPair = Kruskal .iterateEdges(junctionBoxes, closestPairs).last
4353 lastPair._1.x * lastPair._2.x
4454 }
0 commit comments