/
PacketDecoder.kt
125 lines (104 loc) · 3.48 KB
/
PacketDecoder.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
123
124
125
package d16_PacketDecoder
import util.Input
import util.Output
val BITSMap = mapOf(
'0' to "0000",
'1' to "0001",
'2' to "0010",
'3' to "0011",
'4' to "0100",
'5' to "0101",
'6' to "0110",
'7' to "0111",
'8' to "1000",
'9' to "1001",
'A' to "1010",
'B' to "1011",
'C' to "1100",
'D' to "1101",
'E' to "1110",
'F' to "1111",
)
fun main() {
Output.day(16, "Packet Decoder")
val startTime = Output.startTime()
val transmissionBits = ArrayDeque(
Input.parseToListOf<Char>(
rawData = Input.parseAllText(filename = "/input/d16_BITS_transmision.txt")
).flatMap {
BITSMap[it]!!.split("")
.mapNotNull { c -> if (c.isNotBlank()) c.single() else null }
}
)
val decodedTransmission = transmissionBits.getPackets()
Output.part(1, "Sum of Version Numbers", decodedTransmission.first)
Output.part(2, "Evaluated Transmission", decodedTransmission.second)
Output.executionTime(startTime)
}
fun ArrayDeque<Char>.getPackets(): Pair<Int, Long> {
var curBits = ""
val subPackets = mutableListOf<Long>()
for (i in 1..3) curBits += removeFirst()
var version = curBits.toInt(2)
curBits = ""
for (i in 1..3) curBits += removeFirst()
val typeId = curBits.toInt(2)
curBits = ""
when (typeId) {
4 -> { // literal value
val literalChunks = mutableListOf<String>()
do {
while (curBits.length < 5)
curBits += removeFirst()
literalChunks.add(curBits.takeLast(5))
curBits = ""
} while (!literalChunks.last().startsWith('0'))
subPackets += literalChunks.joinToString("") { it.takeLast(4) }.toLong(2)
// no need to recurse for literal values,
// hop down to end return :)
}
else -> { // operator
when (removeFirst().toBitLength()) {
11 -> {
for (i in 1..11) curBits += removeFirst()
val numSubPackets = curBits.toInt(2)
for (i in 1..numSubPackets) {
val p = getPackets()
version += p.first
subPackets += p.second
}
}
else -> {
for (i in 1..15) curBits += removeFirst()
val subPacketsLength = curBits.toInt(2)
val subPacketBits = ArrayDeque<Char>()
for (i in 1..subPacketsLength)
subPacketBits += removeFirst()
while (subPacketBits.size > 0) {
if (subPacketBits.all { it == '0' })
break
val p = subPacketBits.getPackets()
version += p.first
subPackets += p.second
}
}
}
}
}
return Pair(version, subPackets.operateBy(typeId))
}
private fun Char.toBitLength(): Int = with(digitToInt()) {
if (this == 0) 15
else 11
}
fun MutableList<Long>.operateBy(id: Int) =
when (id) {
0 -> sumOf { it }
1 -> reduce { acc, cur -> acc * cur }
2 -> minOf { it }
3 -> maxOf { it }
5 -> if (this[0] > this[1]) 1 else 0
6 -> if (this[0] < this[1]) 1 else 0
7 -> if (this[0] == this[1]) 1 else 0
else -> first() // return literal (4)
}