-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay04GiantSquid.kt
63 lines (49 loc) · 2.32 KB
/
Day04GiantSquid.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package adventofcode.year2021
import adventofcode.Puzzle
import adventofcode.PuzzleInput
class Day04GiantSquid(customInput: PuzzleInput? = null) : Puzzle(customInput) {
private val numbers by lazy { input.lines().first().split(",").map(String::toInt) }
private val boards by lazy {
input
.split("\n\n")
.drop(1)
.map { board -> board.lines().map { row -> row.split(" ").filter(String::isNotBlank).map { Number(it.toInt()) } } }
.map(::Board)
}
private fun playBingo() =
generateSequence(0 to boards.map { board -> board.markNumber(numbers.first()) }) { (previousIndex, previousBoards) ->
previousIndex + 1 to previousBoards.map { board -> board.markNumber(numbers[previousIndex + 1]) }
}
.take(numbers.size)
override fun partOne(): Int {
val firstWinner = playBingo().first { (_, boards) -> boards.any { board -> board.hasWon() } }
val lastDrawnNumber = numbers[firstWinner.first]
val winnerBoard = firstWinner.second.first { board -> board.hasWon() }
return lastDrawnNumber * winnerBoard.sumOfAllUnmarkedNumbers()
}
override fun partTwo(): Int {
val beforeLastWinner = playBingo().last { (_, boards) -> boards.any { board -> !board.hasWon() } }
val lastDrawnNumber = numbers[beforeLastWinner.first + 1]
val winnerBoard = beforeLastWinner.second.first { board -> !board.hasWon() }.markNumber(lastDrawnNumber)
return lastDrawnNumber * winnerBoard.sumOfAllUnmarkedNumbers()
}
companion object {
private data class Number(
val value: Int,
val marked: Boolean = false,
)
private data class Board(
val numbers: List<List<Number>>,
) {
fun markNumber(number: Int) =
copy(numbers = numbers.map { row -> row.map { if (it.value == number) Number(it.value, true) else it } })
fun hasWon() =
when {
(numbers.any { row -> row.all { it.marked } }) -> true
(numbers.first().indices.any { col -> numbers.all { row -> row[col].marked } }) -> true
else -> false
}
fun sumOfAllUnmarkedNumbers() = numbers.flatten().filterNot { it.marked }.sumOf { it.value }
}
}
}