day(21): add sources
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
dacc2a2c37
commit
1c09b90255
2 changed files with 116 additions and 0 deletions
114
src/year2021/day21/Day21.kt
Normal file
114
src/year2021/day21/Day21.kt
Normal file
|
@ -0,0 +1,114 @@
|
|||
package year2021.day21
|
||||
|
||||
import readInput
|
||||
|
||||
interface Die {
|
||||
val rolled: Int
|
||||
fun roll(): Iterable<Int>
|
||||
}
|
||||
|
||||
data class RegularDie(var next: Int = 1, override var rolled: Int = 0) : Die {
|
||||
override fun roll(): Iterable<Int> {
|
||||
val rolls = listOf(next, (next + 1) % 100, (next + 2) % 100)
|
||||
|
||||
rolled += 3
|
||||
next += 3
|
||||
next %= 100
|
||||
|
||||
return rolls
|
||||
}
|
||||
}
|
||||
|
||||
data class DiracDie(
|
||||
val rolls: List<Int> = (3..9).toList(),
|
||||
override val rolled: Int = -1
|
||||
) : Die {
|
||||
override fun roll(): Iterable<Int> = rolls
|
||||
}
|
||||
|
||||
data class Board(
|
||||
val players: MutableList<Int>,
|
||||
val winScore: Int,
|
||||
val die: Die,
|
||||
val scores: MutableList<Int> = mutableListOf(),
|
||||
private var nextPlayer: Int = 0,
|
||||
) {
|
||||
init {
|
||||
if (scores.isEmpty()) {
|
||||
repeat(playersCount) { scores.add(0) }
|
||||
}
|
||||
}
|
||||
|
||||
private val playersCount: Int
|
||||
get() = players.size
|
||||
|
||||
val done: Boolean
|
||||
get() = winner != -1
|
||||
|
||||
private val winner: Int
|
||||
get() = scores.indexOfFirst { it >= winScore }
|
||||
|
||||
val losingScore: Int
|
||||
get() = scores.first { it < winScore }
|
||||
|
||||
private fun playRound(roll: Int) {
|
||||
players[nextPlayer] = (players[nextPlayer] + roll) % 10
|
||||
scores[nextPlayer] += players[nextPlayer] + 1
|
||||
nextPlayer = (nextPlayer + 1) % playersCount
|
||||
}
|
||||
|
||||
fun playRegular() = playRound(die.roll().sum())
|
||||
|
||||
fun playDirac(): MutableList<ULong> {
|
||||
val winCount = mutableListOf<ULong>()
|
||||
repeat(players.size) { winCount.add(0UL) }
|
||||
|
||||
playDirac(winCount, 1UL)
|
||||
|
||||
return winCount
|
||||
}
|
||||
|
||||
private val diracProbabilities = listOf(1, 3, 6, 7, 6, 3, 1).map(Int::toULong)
|
||||
private fun playDirac(winCount: MutableList<ULong>, factor: ULong) {
|
||||
if (done) {
|
||||
winCount[winner] += factor
|
||||
return
|
||||
}
|
||||
|
||||
die.roll().zip(diracProbabilities).forEach { (roll, probability) ->
|
||||
val recursiveBoard = this.copy(players = players.toMutableList(), scores = scores.toMutableList())
|
||||
recursiveBoard.playRound(roll)
|
||||
recursiveBoard.playDirac(winCount, probability * factor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun List<String>.toBoard(): Board {
|
||||
val players = this.map { it.split(": ")[1].toInt() - 1 }.toMutableList()
|
||||
return Board(players, 1000, RegularDie())
|
||||
}
|
||||
|
||||
fun List<String>.toDiracBoard(): Board {
|
||||
val players = this.map { it.split(": ")[1].toInt() - 1 }.toMutableList()
|
||||
return Board(players, 21, DiracDie())
|
||||
}
|
||||
|
||||
fun part1(input: Board): Int {
|
||||
while (!input.done) {
|
||||
input.playRegular()
|
||||
}
|
||||
return input.losingScore * input.die.rolled
|
||||
}
|
||||
|
||||
fun part2(input: Board): ULong = input.playDirac().maxOf { it }
|
||||
|
||||
fun main() {
|
||||
val sample = readInput(21, "sample")
|
||||
val input = readInput(21, "input")
|
||||
|
||||
check(part1(sample.toBoard()) == 739785)
|
||||
println(part1(input.toBoard()))
|
||||
|
||||
check(part2(sample.toDiracBoard()) == 444356092776315UL)
|
||||
println(part2(input.toDiracBoard()))
|
||||
}
|
2
src/year2021/day21/sample.txt
Normal file
2
src/year2021/day21/sample.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Player 1 starting position: 4
|
||||
Player 2 starting position: 8
|
Loading…
Reference in a new issue