generated from kotlin-hands-on/advent-of-code-kotlin-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay04.kt
122 lines (97 loc) · 3.37 KB
/
Day04.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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package year2021.`04`
import readInput
import transpose
private data class Bingos<T>(
val items: List<List<T>>
)
private data class Marked<T>(
val item: T,
var marked: Boolean
)
fun main() {
fun extractListOfNumbers(input: List<String>): List<Int> {
val filteredItems = input.filter { it.isNotBlank() }
val numbers = filteredItems.first()
.split(",")
return numbers.map { it.toInt() }
}
fun extractBingoList(input: List<String>): List<Bingos<Marked<Int>>> {
val filteredItems = input.filter { it.isNotBlank() }
val bingos = filteredItems.drop(1)
.windowed(5, 5)
.map { bingo ->
bingo.map { line ->
line.split(" ")
.filter { it.isNotBlank() }
.map {
Marked(
item = it.toInt(),
marked = false
)
}
}
}
return bingos.map { Bingos(it) }
}
fun Bingos<Marked<Int>>.playRound(number: Int) {
items.forEach { line ->
line.forEach {
if (it.item == number) it.marked = true
}
}
}
fun Bingos<Marked<Int>>.isWinner(): Boolean {
val horizontal = items.any { line -> line.all { it.marked } }
val vertical = transpose(items).any { line -> line.all { it.marked } }
return horizontal || vertical
}
fun Bingos<Marked<Int>>.calculateResult(numberWon: Int): Int {
val sum = this.items.sumOf { line ->
line.sumOf { markedItem ->
markedItem.item.takeIf { !markedItem.marked } ?: 0
}
}
return sum * numberWon
}
fun part1(input: List<String>): Int {
val numbers = extractListOfNumbers(input)
val bingoList = extractBingoList(input)
val iterator = numbers.iterator()
var hasWinner = false
var number = 0
while (!hasWinner) {
number = iterator.next()
bingoList.forEach { it.playRound(number) }
hasWinner = bingoList.any { it.isWinner() }
}
val winner = bingoList.find { it.isWinner() } ?: error("No items found")
return winner.calculateResult(number)
}
fun part2(input: List<String>): Int {
val numbers = extractListOfNumbers(input)
var bingoList = extractBingoList(input)
val iterator = numbers.iterator()
var number = 0
// Run rounds and filter-out winners
while (bingoList.size != 1) {
number = iterator.next()
bingoList.forEach { it.playRound(number) }
val winners = bingoList.filter { it.isWinner() }.toSet()
bingoList = bingoList - winners
}
// Run rounds until last bingo is not won.
val lastBingo = bingoList.first()
while (!lastBingo.isWinner()) {
number = iterator.next()
lastBingo.playRound(number)
}
return lastBingo.calculateResult(number)
}
// test if implementation meets criteria from the description, like:
val testInput = readInput("Day04_test")
val part1Test = part1(testInput)
check(part1Test == 4512)
val input = readInput("Day04")
println(part1(input))
println(part2(input))
}