Skip to content

Commit 7423ab4

Browse files
committed
Day 14
1 parent 0d29a1f commit 7423ab4

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
group = "de.nxll.aoc2022"
88
version = "1.0"
99

10-
val currentDay = 13
10+
val currentDay = 14
1111

1212
repositories {
1313
mavenCentral()

src/day_14/kotlin/Day14.kt

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import kotlin.math.sign
2+
3+
// AOC Day 14
4+
5+
const val rockCharacter = '#'
6+
const val sandCharacter = '.'
7+
const val airCharacter = ' '
8+
const val printCave = false
9+
10+
typealias Cave = Array<CharArray>
11+
12+
fun Cave.print() = forEach { println(it.joinToString(" ")) }.also { println() }
13+
operator fun Cave.get(point: Vector2D) = this[point.y][point.x]
14+
operator fun Cave.set(point: Vector2D, char: Char) {
15+
this[point.y][point.x] = char
16+
}
17+
18+
val sandMovesPriorityOrdered = listOf(Vector2D(0, 1), Vector2D(-1, 1), Vector2D(1, 1))
19+
fun Cave.simulateFallingSand(startPosition: Vector2D): Vector2D {
20+
var currentPosition = startPosition
21+
var isResting = false
22+
23+
while (!isResting) {
24+
sandMovesPriorityOrdered
25+
.map { currentPosition + it }
26+
.filter { it.y in 0..this.lastIndex && it.x in 0..this[0].lastIndex }
27+
.filter { this[it] == airCharacter }
28+
.apply {
29+
if (none()) isResting = true
30+
else currentPosition = first()
31+
}
32+
}
33+
34+
return currentPosition
35+
}
36+
37+
fun part1(cave: Cave, sandSourcePoint: Vector2D) {
38+
var sandUnits = 0
39+
while (true) {
40+
val sandRestingPoint = cave.simulateFallingSand(sandSourcePoint)
41+
if (sandRestingPoint.y == cave.lastIndex - 1) break
42+
sandUnits++
43+
cave[sandRestingPoint] = sandCharacter
44+
}
45+
46+
if (printCave) cave.print()
47+
println("Part 1: The first unit of sand falls into the abyss after $sandUnits sand units have come to rest")
48+
}
49+
50+
fun part2(cave: Cave, sandSourcePoint: Vector2D) {
51+
var sandUnits = 0
52+
while (true) {
53+
val sandRestingPoint = cave.simulateFallingSand(sandSourcePoint)
54+
sandUnits++
55+
cave[sandRestingPoint] = sandCharacter
56+
if (sandRestingPoint == sandSourcePoint) break
57+
}
58+
59+
if (printCave) cave.print()
60+
println("Part 2: $sandUnits sand untis have to come to rest for the source to be blocked")
61+
}
62+
63+
fun String.toPoint() = this.split(",").mapToInt().run { Vector2D(first(), last()) }
64+
fun Cave.deepCopy(): Cave = map { it.toList().toCharArray() }.toTypedArray()
65+
val pointRegex = "\\d+,\\d+".toRegex()
66+
67+
fun main() {
68+
val (cave, sandSourcePoint) = getAOCInput { rawInput ->
69+
val points = pointRegex.findAll(rawInput).map { it.value.toPoint() }
70+
71+
var minX = points.minOf { it.x }
72+
var maxX = points.maxOf { it.x }
73+
val minY = 0 // Sand level
74+
var maxY = points.maxOf { it.y }
75+
76+
77+
val floorHeight = maxY + 2
78+
maxY = floorHeight
79+
minX -= floorHeight
80+
maxX += floorHeight
81+
82+
fun Vector2D.asNormalized() = Vector2D(x - minX, y - minY)
83+
84+
val cave: Cave = Array(maxY - minY + 1) { CharArray(maxX - minX + 1) { airCharacter } }
85+
86+
val sandSourcePoint = Vector2D(500, 0).asNormalized()
87+
cave[sandSourcePoint] = 'S'
88+
89+
val floorPath = Vector2D(minX, floorHeight).asNormalized() to Vector2D(maxX, floorHeight).asNormalized()
90+
91+
val paths = rawInput.trim().lines()
92+
.flatMap { line ->
93+
line
94+
.split(" -> ")
95+
.map { it.toPoint().asNormalized() }
96+
.zipWithNext()
97+
}
98+
.plus(floorPath)
99+
100+
paths.forEach { (start, end) ->
101+
var currentPos = start
102+
103+
val signX = (end.x - start.x).sign
104+
val signY = (end.y - start.y).sign
105+
106+
while (currentPos.x != end.x) {
107+
cave[currentPos] = rockCharacter
108+
currentPos += Vector2D(signX, 0)
109+
cave[currentPos] = rockCharacter
110+
}
111+
112+
while (currentPos.y != end.y) {
113+
cave[currentPos] = rockCharacter
114+
currentPos += Vector2D(0, signY)
115+
cave[currentPos] = rockCharacter
116+
}
117+
}
118+
119+
cave to sandSourcePoint
120+
}
121+
122+
part1(cave.deepCopy(), sandSourcePoint)
123+
part2(cave.deepCopy(), sandSourcePoint)
124+
}

0 commit comments

Comments
 (0)