diff options
Diffstat (limited to 'aoc-2021-kotlin/src/Day25.kt')
-rw-r--r-- | aoc-2021-kotlin/src/Day25.kt | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/aoc-2021-kotlin/src/Day25.kt b/aoc-2021-kotlin/src/Day25.kt new file mode 100644 index 0000000..36a2f75 --- /dev/null +++ b/aoc-2021-kotlin/src/Day25.kt @@ -0,0 +1,87 @@ +object Day25 { + private 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 '.'!") + } + }) + } + } + + private 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 singlePart(input: List<String>) = SeaCucumbers.fromLines(input).simulate() +} + +fun main() { + val testInput = readInputAsLines("Day25_test") + check(Day25.singlePart(testInput) == 58) + + val input = readInputAsLines("Day25") + println(Day25.singlePart(input)) +} |