Den 9., ačkoliv se jevil jednoduše, zákeřnost jeho zadání přišla záhy 🙂 . První část jsem ještě zvládl sám, ale v části druhé jsem měl již perfomance problém. Ačkoliv se mi mé první řešení podařilo zrychlit až 25x, stále to bylo velmi málo. A tak jsem musel zvolit zcela jiný přístup, kde jsem se musel inspirovat řešením ostatních na Kotlin Slacku, což nakonec rychle vedlo ke kýženému cíli:

import com.google.common.collect.Iterables
import com.svetylkovo.rojo.Rojo
import java.io.File

data class ElfPlayer(val id: Int, var score: Long = 0)

data class Marble(val number: Int) {
    var next: Marble = this
    var prev: Marble = this

    fun remove() {
        prev.next = next
        next.prev = prev
    }

    fun add(marble: Marble) {
        next.run {
            next.prev = marble
            marble.next = next
            marble.prev = this
            next = marble
        }
    }
}

class Game(
    val players: List<ElfPlayer>,
    val lastMarbleNumber: Int
) {
    var current = Marble(0)

    fun start() {
        var nextMarbleNumber = 0

        Iterables.cycle(players).forEach { player ->
            if (nextMarbleNumber > lastMarbleNumber) return
            nextTurn(player, ++nextMarbleNumber)
        }
    }

    fun winner() = players.maxBy { it.score }

    private fun nextTurn(player: ElfPlayer, nextMarbleNumber: Int) {
        val nextMarble = Marble(nextMarbleNumber)

        when {
            nextMarbleNumber % 23 == 0 -> {
                player.score += nextMarbleNumber

                moveBackward(7)
                val marbleToRemove = current
                player.score += marbleToRemove.number
                marbleToRemove.remove()

                moveForward(1)
            }
            else -> {
                current.add(nextMarble)
                current = nextMarble
            }
        }

    }

    private fun moveBackward(n: Int) {
        repeat(n) {
            current = current.prev
        }
    }

    private fun moveForward(n: Int) {
        repeat(n) {
            current = current.next
        }
    }

}

fun main() {

    val input = File("input9.txt").readText()

    val (players, lastMarble) = Rojo.asList("\\d+", input).map { it.toInt() }

    //A
    val elfPlayersA = List(players) { ElfPlayer(it + 1) }

    val gameA = Game(elfPlayersA, lastMarble)
    gameA.start()
    println(gameA.winner())

    //B
    val elfPlayersB = List(players) { ElfPlayer(it + 1) }
    val gameB = Game(elfPlayersB, lastMarble * 100)
    gameB.start()

    println(gameB.winner())
}