-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day22.kt
171 lines (138 loc) · 5.3 KB
/
Day22.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package y2021
import general.Day
import java.lang.Integer.max
import java.lang.Integer.min
object Day22 : Day() {
override val name = "Reactor Reboot"
override fun a1() {
val reactor = Array(101) { Array(101) { BooleanArray(101) { false } } }
val input = INPUT.readLines()
for (line in input) {
val toState = line.startsWith("on")
val rawXYZ = line.substringAfter(" ").split(",")
val (fromX, toX) = rawXYZ[0].substring(2).split("..").map { it.toInt() }
val (fromY, toY) = rawXYZ[1].substring(2).split("..").map { it.toInt() }
val (fromZ, toZ) = rawXYZ[2].substring(2).split("..").map { it.toInt() }
for (x in max(-50, fromX)..min(50, toX))
for (y in max(-50, fromY)..min(50, toY))
for (z in max(-50, fromZ)..min(50, toZ))
reactor[x + 50][y + 50][z + 50] = toState
}
println(reactor.sumOf { it.sumOf { it.count { it } } })
}
class Cube(val state: Boolean, val rangeX: IntRange, val rangeY: IntRange, val rangeZ: IntRange) {
fun volume() =
(rangeX.last - rangeX.first + 1L) *
(rangeY.last - rangeY.first + 1L) *
(rangeZ.last - rangeZ.first + 1L)
/**
* @return the cube that is inside both this cube and another cube
*/
fun cross(other: Cube): Cube? {
val crossX = crossAxis(rangeX, other.rangeX) ?: return null
val crossY = crossAxis(rangeY, other.rangeY) ?: return null
val crossZ = crossAxis(rangeZ, other.rangeZ) ?: return null
return Cube(false, crossX, crossY, crossZ)
}
/**
* Adds all cubes into a cubes-list that will be created
* if you subtract another cube from this cube
*/
fun cut(other: Cube, cubes: ArrayList<Cube>) {
// make things go fast!!
// (I really mean it, without this check it will take forever)
if (cross(other) == null) {
cubes += this
return
}
for (rX in listOf(
Int.MIN_VALUE until other.rangeX.first,
other.rangeX,
(other.rangeX.last + 1)..Int.MAX_VALUE
))
for (rY in listOf(
Int.MIN_VALUE until other.rangeY.first,
other.rangeY,
(other.rangeY.last + 1)..Int.MAX_VALUE
))
for (rZ in listOf(
Int.MIN_VALUE until other.rangeZ.first,
other.rangeZ,
(other.rangeZ.last + 1)..Int.MAX_VALUE
))
if (!(rX == other.rangeX && rY == other.rangeY && rZ == other.rangeZ)) {
val cube = cross(Cube(false, rX, rY, rZ))
if (cube != null)
cubes += cube
}
}
companion object {
/**
* @return the range that is inside both ranges
* or null if otherwise
*/
private fun crossAxis(range: IntRange, other: IntRange): IntRange? {
if (other.first in range) {
return other.first..min(range.last, other.last)
}
else if (other.last in range) {
return max(range.first, other.first)..other.last
}
else if (other.first < range.first && other.last > range.last) {
return range
}
return null
}
}
}
override fun a2() {
val steps = ArrayList<Cube>()
// read cubes
for (line in INPUT.readLines()) {
val toState = line.startsWith("on")
val rawXYZ = line.substringAfter(" ").split(",")
val (fromX, toX) = rawXYZ[0].substring(2).split("..").map { it.toInt() }
val (fromY, toY) = rawXYZ[1].substring(2).split("..").map { it.toInt() }
val (fromZ, toZ) = rawXYZ[2].substring(2).split("..").map { it.toInt() }
steps += Cube(toState, fromX..toX, fromY..toY, fromZ..toZ)
}
// handle steps
val currentCubesOn = ArrayList<Cube>()
for (cube in steps) {
if (cube.state) add(currentCubesOn, cube)
else remove(currentCubesOn, cube)
}
// output
println(currentCubesOn.sumOf { it.volume() })
}
/**
* add origin cube to cubesOn-list
* and if needed, before adding, cut origin cube into small
* pieces if specific parts are already inside the cubesOn-list
*/
private fun add(cubesOn: ArrayList<Cube>, origin: Cube) {
val cubes = ArrayList<Cube>()
val tempAdd = ArrayList<Cube>()
cubes += origin
for (other in cubesOn) {
for (cube in cubes)
cube.cut(other, tempAdd)
cubes.clear()
cubes += tempAdd
tempAdd.clear()
}
cubesOn += cubes
}
/**
* cut every cube into small pieces and remove
* the piece that is equal to the other-cube
*/
private fun remove(cubes: ArrayList<Cube>, other: Cube) {
val tempAdd = ArrayList<Cube>()
for (cube in cubes)
cube.cut(other, tempAdd)
cubes.clear()
cubes += tempAdd
tempAdd.clear()
}
}