From 1c09b90255e9a46d4a7868b15ae2744eff728a0d Mon Sep 17 00:00:00 2001 From: Matej Focko Date: Tue, 21 Dec 2021 20:27:24 +0100 Subject: [PATCH] day(21): add sources Signed-off-by: Matej Focko --- src/year2021/day21/Day21.kt | 114 ++++++++++++++++++++++++++++++++++ src/year2021/day21/sample.txt | 2 + 2 files changed, 116 insertions(+) create mode 100644 src/year2021/day21/Day21.kt create mode 100644 src/year2021/day21/sample.txt diff --git a/src/year2021/day21/Day21.kt b/src/year2021/day21/Day21.kt new file mode 100644 index 0000000..d8ee73a --- /dev/null +++ b/src/year2021/day21/Day21.kt @@ -0,0 +1,114 @@ +package year2021.day21 + +import readInput + +interface Die { + val rolled: Int + fun roll(): Iterable +} + +data class RegularDie(var next: Int = 1, override var rolled: Int = 0) : Die { + override fun roll(): Iterable { + val rolls = listOf(next, (next + 1) % 100, (next + 2) % 100) + + rolled += 3 + next += 3 + next %= 100 + + return rolls + } +} + +data class DiracDie( + val rolls: List = (3..9).toList(), + override val rolled: Int = -1 +) : Die { + override fun roll(): Iterable = rolls +} + +data class Board( + val players: MutableList, + val winScore: Int, + val die: Die, + val scores: MutableList = 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 { + val winCount = mutableListOf() + 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, 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.toBoard(): Board { + val players = this.map { it.split(": ")[1].toInt() - 1 }.toMutableList() + return Board(players, 1000, RegularDie()) +} + +fun List.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())) +} diff --git a/src/year2021/day21/sample.txt b/src/year2021/day21/sample.txt new file mode 100644 index 0000000..6dec3f4 --- /dev/null +++ b/src/year2021/day21/sample.txt @@ -0,0 +1,2 @@ +Player 1 starting position: 4 +Player 2 starting position: 8 \ No newline at end of file