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())
}