generated from Jadarma/advent-of-code-kotlin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathY2015D18.kt
96 lines (80 loc) · 3.22 KB
/
Y2015D18.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
package aockt.y2015
import io.github.jadarma.aockt.core.Solution
object Y2015D18 : Solution {
private class GameOfLife(val width: Int, val height: Int, val santaVariation: Boolean = false) {
private val state = Array(width + 2) { BooleanArray(height + 2) { false } }
init {
stuckLights()
}
private fun validateCoordinates(x: Int, y: Int) {
if (x !in 0 until width || y !in 0 until height)
throw IndexOutOfBoundsException("Invalid coordinate: $x - $y")
}
operator fun get(x: Int, y: Int): Boolean {
validateCoordinates(x, y)
return state[x + 1][y + 1]
}
operator fun set(x: Int, y: Int, isAlive: Boolean) {
validateCoordinates(x, y)
state[x + 1][y + 1] = isAlive
}
/** Returns how many cells are alive in the current state of the game. */
fun aliveCells() = state.sumOf { row -> row.count { it } }
/** Passes a generation and updates the internal state. */
fun playGeneration() {
val currentGen = Array(state.size) { state[it].copyOf() }
for (x in 1..width) {
for (y in 1..height) {
val v = currentGen[x][y]
val n = currentGen.neighbourCount(x, y)
state[x][y] = when {
v && n in 2..3 -> true
!v && n == 3 -> true
else -> false
}
}
}
stuckLights()
}
/** Returns how many neighbouring cells around this point are alive. */
private fun Array<BooleanArray>.neighbourCount(x: Int, y: Int): Int {
var sum = 0
for (i in x - 1..x + 1) {
for (j in y - 1..y + 1) {
sum += this[i][j].toInt()
}
}
return sum - this[x][y].toInt()
}
private fun Boolean.toInt() = if (this) 1 else 0
/** If this is the [santaVariation], override the four corner cells to be alive. */
private fun stuckLights() {
if (!santaVariation) return
state[1][1] = true
state[width][1] = true
state[1][height] = true
state[width][height] = true
}
}
/** Parses the [input] lines and builds a new [GameOfLife] with the given initial state. */
private fun parseInput(input: List<String>, santaVariation: Boolean = false) =
GameOfLife(input.first().length, input.size, santaVariation).apply {
input.forEachIndexed { y, string ->
string.forEachIndexed { x, c ->
this[x, y] = when (c) {
'#' -> true
'.' -> false
else -> throw IllegalArgumentException("Invalid input.")
}
}
}
}
override fun partOne(input: String) = parseInput(input.lines()).run {
repeat(100) { playGeneration() }
aliveCells()
}
override fun partTwo(input: String) = parseInput(input.lines(), santaVariation = true).run {
repeat(100) { playGeneration() }
aliveCells()
}
}