generated from Jadarma/advent-of-code-kotlin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathY2021D25.kt
77 lines (67 loc) · 2.55 KB
/
Y2021D25.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
package aockt.y2021
import aockt.util.parse
import aockt.util.spacial.*
import io.github.jadarma.aockt.core.Solution
object Y2021D25 : Solution {
private class Trench(private val data: MutableGrid<Node>) : Grid<Trench.Node> by data {
/** The type of nodes the trench map can have. */
enum class Node { Empty, East, South }
/** Return the point this cucumber will occupy, if a legal move is available. */
private fun GridCell<Node>.moveTarget(): Point? {
val direction = when (value) {
Node.Empty -> return null
Node.East -> Direction.Right
Node.South -> Direction.Down
}
return position
.move(direction)
.run {
copy(
x = if (x >= data.width) 0 else x,
y = if (y < 0) data.height - 1L else y,
)
}
.takeIf { data[it] == Node.Empty }
}
/** Perform the cucumber move. */
private fun GridCell<Node>.moveCucumber() {
val target = moveTarget() ?: error("Illegal move.")
val cucumber = data[position]
data[position] = Node.Empty
data[target] = cucumber
}
/**
* Mutate the trench, calculating the movements of the sea cucumbers, and return whether any modification
* took place since the previous state.
*/
fun step(): Boolean {
fun moveAndCountCucumbers(type: Node): Int =
data.points()
.filter { it.value == type }
.filter { it.moveTarget() != null }
.toList() // Force evaluation of all cucumbers before moving.
.onEach { it.moveCucumber() }
.count()
return moveAndCountCucumbers(Node.East) + moveAndCountCucumbers(Node.South) > 0
}
}
/** Parse the [input] and return the state of the [Trench]. */
private fun parseInput(input: String): Trench = parse {
MutableGrid(input) {
when (it) {
'.' -> Trench.Node.Empty
'>' -> Trench.Node.East
'v' -> Trench.Node.South
else -> error("Invalid input")
}
}.let(::Trench)
}
override fun partOne(input: String): Int {
val trench = parseInput(input)
var steps = 0
while (trench.step()) {
if (steps++ > 1000) error("Giving up.")
}
return steps + 1
}
}