/
Day14.kt
84 lines (70 loc) · 3.07 KB
/
Day14.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.akikanellis.adventofcode.year2022
import com.akikanellis.adventofcode.year2022.utils.Point
object Day14 {
private val SAND_STARTING_POINT = Point(500, 0)
fun unitsOfSandRestingBeforeFreefall(input: String) =
unitsOfSandResting(input, sandFreeFalls = true)
fun unitsOfSandRestingWhenFull(input: String) =
unitsOfSandResting(input, sandFreeFalls = false)
private fun unitsOfSandResting(input: String, sandFreeFalls: Boolean): Int {
val rockAndSandPoints = scannedRockPoints(input)
val minRockXWithoutFloor = rockAndSandPoints.minOf { it.x }
val maxRockXWithoutFloor = rockAndSandPoints.maxOf { it.x }
val maxRockYWithoutFloor = rockAndSandPoints.maxOf { it.y }
rockAndSandPoints += floorRockPoints(
minRockXWithoutFloor,
maxRockXWithoutFloor,
maxRockYWithoutFloor
)
var moreSandCanFit = true
var amountOfRestingSand = 0
while (moreSandCanFit) {
var currentSandPoint = SAND_STARTING_POINT
var sandIsMoving = true
while (sandIsMoving) {
if (sandFreeFalls && currentSandPoint.y > maxRockYWithoutFloor) {
sandIsMoving = false
moreSandCanFit = false
} else if (currentSandPoint.plusY() !in rockAndSandPoints) {
currentSandPoint = currentSandPoint.plusY()
} else if (currentSandPoint.minusX().plusY() !in rockAndSandPoints) {
currentSandPoint = currentSandPoint.minusX().plusY()
} else if (currentSandPoint.plusX().plusY() !in rockAndSandPoints) {
currentSandPoint = currentSandPoint.plusX().plusY()
} else {
rockAndSandPoints += currentSandPoint
amountOfRestingSand++
sandIsMoving = false
}
}
if (SAND_STARTING_POINT in rockAndSandPoints) {
moreSandCanFit = false
}
}
return amountOfRestingSand
}
private fun scannedRockPoints(input: String) = input
.lines()
.filter { it.isNotBlank() }
.flatMap {
it
.split(" -> ")
.map { coordinates ->
coordinates
.split(",")
.let { xAndY -> Point(xAndY[0].toInt(), xAndY[1].toInt()) }
}
.zipWithNext()
.flatMap { (leftPoint, rightPoint) ->
(leftPoint.x..rightPoint.x).map { x -> leftPoint.copy(x = x) } +
(leftPoint.y..rightPoint.y).map { y -> leftPoint.copy(y = y) } +
(rightPoint.x..leftPoint.x).map { x -> rightPoint.copy(x = x) } +
(rightPoint.y..leftPoint.y).map { y -> rightPoint.copy(y = y) }
}
}.toMutableSet()
private fun floorRockPoints(
minX: Int,
maxX: Int,
maxY: Int
) = (minX - maxY..maxX + maxY).map { x -> Point(x, maxY + 2) }
}