diff options
author | tchojnacki <tomaszchojnacki2001@gmail.com> | 2022-08-11 19:24:23 +0200 |
---|---|---|
committer | tchojnacki <tomaszchojnacki2001@gmail.com> | 2022-08-11 19:24:23 +0200 |
commit | 0f1e145b80813ae2331b7dac5ace0c589654ad2a (patch) | |
tree | 25483b8239436dd5aed2fee8811caf0ba893c0bb /aoc-2021-kotlin/src/Day04.kt | |
parent | 85fb0396bed6a2129b12392941103924b1ab55be (diff) | |
download | gleam_aoc2020-0f1e145b80813ae2331b7dac5ace0c589654ad2a.tar.gz gleam_aoc2020-0f1e145b80813ae2331b7dac5ace0c589654ad2a.zip |
Move subproject to avoid IntelliJ module name issues
Diffstat (limited to 'aoc-2021-kotlin/src/Day04.kt')
-rw-r--r-- | aoc-2021-kotlin/src/Day04.kt | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/aoc-2021-kotlin/src/Day04.kt b/aoc-2021-kotlin/src/Day04.kt new file mode 100644 index 0000000..96cdf3b --- /dev/null +++ b/aoc-2021-kotlin/src/Day04.kt @@ -0,0 +1,97 @@ +object Day04 { + private class Bingo(private val revealQueue: ArrayDeque<Int>, private val boards: List<Board>) { + companion object { + fun fromString(input: String): Bingo { + val sections = input.trim().split("(\\r?\\n){2}".toRegex()) + + val revealQueueString = sections.first() + val revealQueue = ArrayDeque(revealQueueString.split(",").map(String::toInt)) + + val boards = sections.drop(1).map { Board.fromMatrixString(it) } + + return Bingo(revealQueue, boards) + } + } + + fun getResults() = sequence { + while (revealQueue.isNotEmpty() && boards.any { !it.didWin }) { + val number = revealQueue.removeFirst() + + for (board in boards.filter { !it.didWin }) { + board.reveal(number) + + if (board.didWin) { + yield(board.sumOfUnmarked * number) + } + } + } + } + + private class Board(private var rows: List<List<Square>>) { + companion object { + fun fromMatrixString(matrixString: String): Board = Board( + matrixString.trim().split("\\r?\\n".toRegex()).map { rowString -> + rowString.trim().split("\\s+".toRegex()).map { squareString -> + Square.Unmarked(squareString.toInt()) + } + } + ) + + private const val SIZE = 5 + + private val ROWS = (0 until SIZE).map { row -> + (0 until SIZE).map { square -> + Pair(row, square) + } + } + + private val COLUMNS = (0 until SIZE).map { column -> + (0 until SIZE).map { square -> + Pair(square, column) + } + } + + private val WINNING_CONFIGURATIONS = ROWS + COLUMNS + } + + fun reveal(number: Int) { + rows = rows.map { row -> + row.map { square -> + if (square is Square.Unmarked && square.number == number) Square.Marked else square + } + } + } + + val didWin: Boolean + get() = WINNING_CONFIGURATIONS.any { configuration -> + configuration.all { (row, column) -> rows[row][column] is Square.Marked } + } + + val sumOfUnmarked: Int + get() = rows.fold(0) { rowAcc, row -> + rowAcc + row.fold(0) { squareAcc, square -> + squareAcc + if (square is Square.Unmarked) square.number else 0 + } + } + + sealed class Square { + object Marked : Square() + class Unmarked(val number: Int) : Square() + } + } + } + + fun bothParts(input: String) = Bingo.fromString(input).getResults().let { it.first() to it.last() } +} + +fun main() { + val testInput = readInputAsString("Day04_test") + val testOutput = Day04.bothParts(testInput) + check(testOutput.first == 4512) + check(testOutput.second == 1924) + + val input = readInputAsString("Day04") + val output = Day04.bothParts(input) + println(output.first) + println(output.second) +} |