-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day18.kt
102 lines (81 loc) · 3.47 KB
/
Day18.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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package aoc.years.year2022
import aoc.Day
import kotlin.math.absoluteValue
@Year2022
class Day18 : Day() {
override fun solvePart1(input: List<String>): Any {
return LavaDroplet.of(input)
.countExposedSides()
}
override fun solvePart2(input: List<String>): Any {
return LavaDroplet.of(input)
.countExposedExternalSides()
}
}
private class LavaDroplet(val lavaDroplets: List<Triple<Int, Int, Int>>) {
val lavaDroplet: List<List<List<Char>>>
companion object {
fun of(input: List<String>): LavaDroplet {
val lavaDroplets = input
.map { it.split(",") }
.map { (x, y, z) -> Triple(x.toInt(), y.toInt(), z.toInt()) }
return LavaDroplet(lavaDroplets)
}
}
init {
val largestX = lavaDroplets.maxOf { it.first }
val largestY = lavaDroplets.maxOf { it.second }
val largestZ = lavaDroplets.maxOf { it.third }
lavaDroplet = (0..largestX).map {
(0..largestY).map {
(0..largestZ).map {
'.'
}.toMutableList()
}.toMutableList()
}.toMutableList()
lavaDroplets.forEach { lavaDroplet[it.first][it.second][it.third] = '#' }
}
fun countExposedSides(): Int {
return lavaDroplets.sumOf { it.countExposedSides() }
}
fun countExposedExternalSides(): Int {
return lavaDroplets.sumOf { it.countExposedExternalSides() }
}
private fun Triple<Int, Int, Int>.countExposedSides(): Int {
return 6 - countAdjacentCubesX() - countAdjacentCubesY() - countAdjacentCubesZ()
}
private fun Triple<Int, Int, Int>.countAdjacentCubesX(): Int {
return lavaDroplets.count { it.first.minus(this.first).absoluteValue == 1 && it.second == this.second && it.third == this.third }
}
private fun Triple<Int, Int, Int>.countAdjacentCubesY(): Int {
return lavaDroplets.count { it.second.minus(this.second).absoluteValue == 1 && it.first == this.first && it.third == this.third }
}
private fun Triple<Int, Int, Int>.countAdjacentCubesZ(): Int {
return lavaDroplets.count { it.third.minus(this.third).absoluteValue == 1 && it.first == this.first && it.second == this.second }
}
private fun Triple<Int, Int, Int>.countExposedExternalSides(): Int {
return this.getSides().count { it.isConnectedToOutside(mutableSetOf(it)) }
}
private fun Triple<Int, Int, Int>.isConnectedToOutside(visited: MutableSet<Triple<Int, Int, Int>>): Boolean {
if (this.first !in lavaDroplet.indices
|| this.second !in lavaDroplet.first().indices
|| this.third !in lavaDroplet.first().first().indices
) {
return true // reached border
}
if (lavaDroplet[this.first][this.second][this.third] == '#') {
return false
}
return this.getSides()
.filter { it !in visited }
.also { visited.addAll(it) }
.any { it.isConnectedToOutside(visited) }
}
private fun Triple<Int, Int, Int>.getSides(): List<Triple<Int, Int, Int>> {
return listOf(
Triple(this.first - 1, this.second, this.third), Triple(this.first + 1, this.second, this.third),
Triple(this.first, this.second - 1, this.third), Triple(this.first, this.second + 1, this.third),
Triple(this.first, this.second, this.third - 1), Triple(this.first, this.second, this.third + 1)
)
}
}