Skip to content

Commit 744aa6c

Browse files
committed
Clean up 2025 day 9 part 2
1 parent 002a24f commit 744aa6c

File tree

1 file changed

+33
-58
lines changed
  • src/main/scala/eu/sim642/adventofcode2025

1 file changed

+33
-58
lines changed

src/main/scala/eu/sim642/adventofcode2025/Day9.scala

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package eu.sim642.adventofcode2025
22

33
import eu.sim642.adventofcode2018.Day11.SumGrid
4-
import eu.sim642.adventofcodelib.box.Box
5-
import eu.sim642.adventofcodelib.pos.Pos
64
import eu.sim642.adventofcodelib.SeqImplicits.*
5+
import eu.sim642.adventofcodelib.box.Box
76
import eu.sim642.adventofcodelib.graph.{BFS, GraphTraversal, UnitNeighbors}
7+
import eu.sim642.adventofcodelib.pos.Pos
88

9-
import scala.collection.immutable.SortedSet
109
import scala.collection.mutable
1110

1211
object Day9 {
@@ -36,25 +35,20 @@ object Day9 {
3635
class ArrayPartialSumGrid(f: Pos => Int, box: Box) extends SumGrid {
3736
val Box(min, max) = box
3837
val Pos(width, height) = max - min + Pos(1, 1)
39-
val partialSums: mutable.ArraySeq[mutable.ArraySeq[Int]] = mutable.ArraySeq.fill(height, width)(0)
40-
// TODO: should be larger by 1 to allow min-coordinate queries?
41-
42-
for (y <- 0 until height) {
43-
for (x <- 0 until width) {
44-
val pos = min + Pos(x, y)
45-
val sum =
46-
(if (y >= 1) partialSums(y - 1)(x) else 0) +
47-
(if (x >= 1) partialSums(y)(x - 1) else 0) -
48-
(if (x >= 1 && y >= 1) partialSums(y - 1)(x - 1) else 0) +
49-
f(pos)
38+
val partialSums: mutable.ArraySeq[mutable.ArraySeq[Int]] = mutable.ArraySeq.fill(height + 1, width + 1)(0) // larger by 1 to allow min-coordinate queries
39+
40+
for (y <- 1 until height + 1) {
41+
for (x <- 1 until width + 1) {
42+
val pos = min + Pos(x - 1, y - 1)
43+
val sum = partialSums(y - 1)(x) + partialSums(y)(x - 1) - partialSums(y - 1)(x - 1) + f(pos)
5044
partialSums(y)(x) = sum
5145
}
5246
}
5347

5448
override def sumBox(box: Box): Int = {
5549
//val Box(topLeft, bottomRight) = box
56-
val topLeft = box.min - min
57-
val bottomRight = box.max - min
50+
val topLeft = box.min - min + Pos(1, 1)
51+
val bottomRight = box.max - min + Pos(1, 1)
5852
val bottomLeft1 = Pos(topLeft.x - 1, bottomRight.y)
5953
val topRight1 = Pos(bottomRight.x, topLeft.y - 1)
6054
val topLeft1 = Pos(topLeft.x - 1, topLeft.y - 1)
@@ -63,32 +57,29 @@ object Day9 {
6357
}
6458

6559
object Part2 extends Part {
66-
override def makeIsValid(redTiles: Seq[Pos]): Box => Boolean = {
67-
// TODO: clean up
68-
// TODO: optimize (with polygon checks?)
60+
def makeCompressPos(redTiles: Seq[Pos]): Pos => Pos = {
6961
val xs = redTiles.map(_.x).distinct.sorted
7062
val ys = redTiles.map(_.y).distinct.sorted
71-
//println(xs)
72-
//println(ys)
7363

74-
def mapPos(p: Pos): Pos =
64+
p =>
7565
Pos(xs.indexOf(p.x) * 2 + 1, ys.indexOf(p.y) * 2 + 1) // leave edge around for fill
66+
// it's much faster to do the +1-s here than add Pos(1, 1) below
67+
}
7668

77-
val grid = mutable.ArraySeq.fill(ys.size * 2 - 1 + 2, xs.size * 2 - 1 + 2)('.')
69+
override def makeIsValid(redTiles: Seq[Pos]): Box => Boolean = {
70+
val compressPos = makeCompressPos(redTiles)
71+
def compressBox(box: Box): Box =
72+
Box(compressPos(box.min), compressPos(box.max))
7873

79-
for ((redTile1, redTile2) <- redTiles lazyZip redTiles.rotateLeft(1)) {
80-
val gridPos1 = mapPos(redTile1)
81-
val gridPos2 = mapPos(redTile2)
82-
for (gridPos <- Box.bounding(Seq(gridPos1, gridPos2)).iterator)
83-
grid(gridPos.y)(gridPos.x) = 'X'
84-
}
74+
val originalBox = Box.bounding(redTiles)
75+
val compressedBox@Box(_, compressedMax) = compressBox(originalBox)
8576

86-
for (redTile <- redTiles) {
87-
val gridPos = mapPos(redTile)
88-
//println((redTile, gridPos))
89-
grid(gridPos.y)(gridPos.x) = '#'
77+
val grid = mutable.ArraySeq.fill(compressedMax.y + 2, compressedMax.x + 2)(false) // leave edge around for fill
78+
// TODO: why need +2?
79+
for ((redTile1, redTile2) <- redTiles lazyZip redTiles.rotateLeft(1)) {
80+
for (pos <- compressBox(Box.bounding(Seq(redTile1, redTile2))).iterator)
81+
grid(pos.y)(pos.x) = true
9082
}
91-
9283
//for (row <- grid) {
9384
// for (cell <- row)
9485
// print(cell)
@@ -99,40 +90,24 @@ object Day9 {
9990
override val startNode: Pos = Pos.zero
10091

10192
override def unitNeighbors(pos: Pos): IterableOnce[Pos] =
102-
Pos.axisOffsets.map(pos + _).filter(p => p.x >= 0 && p.y >= 0 && p.y < grid.size && p.x < grid(p.y).size && grid(p.y)(p.x) == '.')
93+
Pos.axisOffsets.map(pos + _).filter(p => p.x >= 0 && p.y >= 0 && p.y < grid.size && p.x < grid(p.y).size && !grid(p.y)(p.x))
10394
}
104-
10595
val outside = BFS.traverse(graphTraversal).nodes
10696

107-
val outsideSumGrid = new ArrayPartialSumGrid(pos => if (outside(pos)) 1 else 0, Box(Pos.zero, Pos(xs.size * 2, ys.size * 2)))
108-
97+
val outsideSumGrid = new ArrayPartialSumGrid(pos => if (outside(pos)) 1 else 0, compressedBox)
10998
def isValid(box: Box): Boolean = {
110-
val gridBox = Box(mapPos(box.min), mapPos(box.max))
111-
//!gridBox.iterator.exists(outside)
112-
outsideSumGrid.sumBox(gridBox) == 0
99+
val compressedBox = Box(compressPos(box.min), compressPos(box.max))
100+
//!compressedBox.iterator.exists(outside)
101+
outsideSumGrid.sumBox(compressedBox) == 0
113102
}
114103

115104
isValid
116105
}
117106
}
118107

119-
/*object Part2 extends Part {
120-
override def largestArea(redTiles: Seq[Pos]): Long = {
121-
122-
def isValid(box: Box): Boolean = {
123-
val boxCorners = Seq(box.min, Pos(box.max.x, box.min.y), box.max, Pos(box.min.x, box.max.y))
124-
???
125-
}
126-
127-
(for {
128-
// faster than combinations(2)
129-
(p1, i) <- redTiles.iterator.zipWithIndex
130-
p2 <- redTiles.view.slice(i + 1, redTiles.size).iterator
131-
box = Box.bounding(Seq(p1, p2))
132-
if isValid(box)
133-
} yield box.size[Long]).max
134-
}
135-
}*/
108+
// TODO: line of sight in all directions solution (single iteration over corners, not all pairs!)
109+
// TODO: glguy's solution
110+
// TODO: polygon-based solution?
136111

137112
def parseRedTile(s: String): Pos = s match {
138113
case s"$x,$y" => Pos(x.toInt, y.toInt)

0 commit comments

Comments
 (0)