aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md6
-rw-r--r--src/Day25.kt85
2 files changed, 88 insertions, 3 deletions
diff --git a/README.md b/README.md
index a055eac..34bf6fb 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# Advent of Code 2021 in Kotlin
![Kotlin](https://img.shields.io/badge/Kotlin-grey?logo=Kotlin)
-![](https://img.shields.io/badge/⭐%20stars-36-yellow)
-![](https://img.shields.io/badge/📅%20days-18-blue)
+![](https://img.shields.io/badge/⭐%20stars-37-yellow)
+![](https://img.shields.io/badge/📅%20days-19-blue)
Welcome to the Advent of Code[^aoc] Kotlin project created by [tchojnacki][github] using
the [Advent of Code Kotlin Template][template] delivered by JetBrains. See other solutions [here][awesome].
@@ -35,7 +35,7 @@ the [Advent of Code Kotlin Template][template] delivered by JetBrains. See other
| Day 22: Reactor Reboot | | |
| Day 23: Amphipod | | |
| Day 24: Arithmetic Logic Unit | | |
-| Day 25: Sea Cucumber | | |
+| Day 25: Sea Cucumber | 🌟 | |
[^aoc]:
[Advent of Code][aoc] – An annual event of Christmas-oriented programming challenges started December 2015.
diff --git a/src/Day25.kt b/src/Day25.kt
new file mode 100644
index 0000000..309c15e
--- /dev/null
+++ b/src/Day25.kt
@@ -0,0 +1,85 @@
+class SeaCucumbers(private val width: Int, private val height: Int, private val matrix: Array<SeaTile>) {
+ companion object {
+ fun fromLines(lines: List<String>) =
+ Pos2D(
+ lines.getOrNull(0)?.length ?: throw IllegalArgumentException("Sea must have a non-zero height!"),
+ lines.size
+ ).let { size ->
+ SeaCucumbers(size.x, size.y, Array(size.x * size.y) {
+ when (val char = lines[it / size.x][it % size.x]) {
+ '>' -> SeaTile.Cucumber.EastFacing
+ 'v' -> SeaTile.Cucumber.SouthFacing
+ '.' -> SeaTile.EmptyTile
+ else -> throw IllegalArgumentException("Found '$char', expected '>', 'v' or '.'!")
+ }
+ })
+ }
+ }
+
+ sealed class SeaTile {
+ object EmptyTile : SeaTile()
+ sealed class Cucumber : SeaTile() {
+ object EastFacing : Cucumber()
+ object SouthFacing : Cucumber()
+ }
+ }
+
+ private fun moveIndex(index: Int, offset: Pos2D) =
+ ((index / width + offset.y) % height) * width + (index + offset.x) % width
+
+ private inline fun <reified T : SeaTile.Cucumber> stepDirection(pos: Pos2D) {
+ matrix
+ .asSequence()
+ .withIndex()
+ .map { (index, seaTile) ->
+ val nextIndex = moveIndex(index, pos)
+ if (seaTile is T && matrix[nextIndex] is SeaTile.EmptyTile) {
+ index to nextIndex
+ } else {
+ null
+ }
+ }
+ .filterNotNull()
+ .toList()
+ .forEach { (index, nextIndex) ->
+ matrix[nextIndex] = matrix[index].also { matrix[index] = SeaTile.EmptyTile }
+ }
+ }
+
+ private fun stepOnce() {
+ stepDirection<SeaTile.Cucumber.EastFacing>(Pos2D(1, 0))
+ stepDirection<SeaTile.Cucumber.SouthFacing>(Pos2D(0, 1))
+ }
+
+ fun simulate(): Int {
+ var count = 0
+
+ do {
+ val previousHashCode = matrix.contentHashCode()
+ stepOnce()
+ count++
+ } while (matrix.contentHashCode() != previousHashCode)
+
+ return count
+ }
+
+ override fun toString(): String = matrix
+ .withIndex()
+ .joinToString("") { (index, seaTile) ->
+ when (seaTile) {
+ SeaTile.Cucumber.EastFacing -> ">"
+ SeaTile.Cucumber.SouthFacing -> "v"
+ SeaTile.EmptyTile -> "."
+ } + (if (index % width == width - 1) "\n" else "")
+ }
+}
+
+fun main() {
+ fun calculate(input: List<String>) = SeaCucumbers.fromLines(input).simulate()
+
+ val testInput = readInputAsLines("Day25_test")
+ check(calculate(testInput) == 58)
+
+ val input = readInputAsLines("Day25")
+ println(calculate(input))
+}