2021-12-20 22:52:18 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
start := time.Now()
|
|
|
|
partOne()
|
|
|
|
duration := time.Since(start)
|
|
|
|
partTwo()
|
|
|
|
duration2 := time.Since(start)
|
|
|
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
|
|
|
}
|
|
|
|
|
|
|
|
var hexMap = map[rune][]uint8{
|
|
|
|
'0': {0, 0, 0, 0},
|
|
|
|
'1': {0, 0, 0, 1},
|
|
|
|
'2': {0, 0, 1, 0},
|
|
|
|
'3': {0, 0, 1, 1},
|
|
|
|
'4': {0, 1, 0, 0},
|
|
|
|
'5': {0, 1, 0, 1},
|
|
|
|
'6': {0, 1, 1, 0},
|
|
|
|
'7': {0, 1, 1, 1},
|
|
|
|
'8': {1, 0, 0, 0},
|
|
|
|
'9': {1, 0, 0, 1},
|
|
|
|
'A': {1, 0, 1, 0},
|
|
|
|
'B': {1, 0, 1, 1},
|
|
|
|
'C': {1, 1, 0, 0},
|
|
|
|
'D': {1, 1, 0, 1},
|
|
|
|
'E': {1, 1, 1, 0},
|
|
|
|
'F': {1, 1, 1, 1},
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeScanner(test bool) *bufio.Scanner {
|
|
|
|
var f *os.File
|
|
|
|
if test {
|
|
|
|
f, _ = os.Open("inputs/testinput")
|
|
|
|
} else {
|
|
|
|
f, _ = os.Open("inputs/input")
|
|
|
|
}
|
|
|
|
reader := bufio.NewReader(f)
|
|
|
|
return bufio.NewScanner(reader)
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseNumber(stream []uint8, length int) int64 {
|
|
|
|
result := int64(0)
|
|
|
|
for i := 0; i < length; i++ {
|
|
|
|
result += int64(stream[i]) << (length - 1 - i)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
type packet struct {
|
|
|
|
version int64
|
|
|
|
typeID int64
|
|
|
|
subPackets []packet
|
|
|
|
encodedNumber int64
|
|
|
|
}
|
|
|
|
|
|
|
|
func getPacketVersion(stream []uint8) int64 {
|
|
|
|
return parseNumber(stream, 3)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getPacketType(stream []uint8) int64 {
|
|
|
|
return parseNumber(stream, 3)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSubpacketLength(t uint8, stream []uint8) (int, int64) {
|
|
|
|
if t == 0 {
|
|
|
|
return 15, parseNumber(stream, 15)
|
|
|
|
}
|
|
|
|
if t == 1 {
|
|
|
|
return 11, parseNumber(stream, 11)
|
|
|
|
}
|
|
|
|
return 0, 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func parsePayload(stream []uint8) (int64, int) {
|
|
|
|
num := []uint8{}
|
|
|
|
pos := 0
|
|
|
|
chars := 0
|
|
|
|
for {
|
|
|
|
currentsegment := stream[pos : pos+5]
|
|
|
|
chars += 4
|
|
|
|
num = append(num, currentsegment[1:5]...)
|
|
|
|
pos += 5
|
|
|
|
if currentsegment[0] == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return parseNumber(num, chars), pos
|
|
|
|
}
|
|
|
|
|
2021-12-20 23:42:36 +00:00
|
|
|
func parsePackets(stream []uint8) (int, packet) {
|
2021-12-20 22:52:18 +00:00
|
|
|
if len(stream) <= 7 {
|
2021-12-20 23:42:36 +00:00
|
|
|
return 0, packet{}
|
2021-12-20 22:52:18 +00:00
|
|
|
}
|
|
|
|
parsedPacket := packet{}
|
|
|
|
parsedPacket.version = getPacketVersion(stream[0:3])
|
|
|
|
parsedPacket.typeID = getPacketType(stream[3:6])
|
|
|
|
if parsedPacket.typeID == 4 {
|
|
|
|
encoded, consumed := parsePayload(stream[6:])
|
|
|
|
parsedPacket.encodedNumber = encoded
|
2021-12-20 23:42:36 +00:00
|
|
|
return consumed + 6, parsedPacket // 6 is packet header length
|
2021-12-20 22:52:18 +00:00
|
|
|
} else {
|
|
|
|
parsed := 0
|
|
|
|
size, subpacketlength := getSubpacketLength(stream[6], stream[7:])
|
|
|
|
for {
|
|
|
|
consumed, subs := parsePackets(stream[7+size+parsed:])
|
2021-12-20 23:42:36 +00:00
|
|
|
parsedPacket.subPackets = append(parsedPacket.subPackets, subs)
|
2021-12-20 22:52:18 +00:00
|
|
|
parsed += consumed
|
|
|
|
if size == 11 && int64(len(parsedPacket.subPackets)) == subpacketlength {
|
2021-12-20 23:42:36 +00:00
|
|
|
return parsed + 7 + size, parsedPacket
|
2021-12-20 22:52:18 +00:00
|
|
|
|
|
|
|
} else if size == 15 && int64(parsed) > subpacketlength || consumed == 0 {
|
2021-12-20 23:42:36 +00:00
|
|
|
return parsed + 7 + size, parsedPacket
|
2021-12-20 22:52:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-20 23:42:36 +00:00
|
|
|
func countVersions(pac packet) int {
|
|
|
|
i := int(pac.version)
|
|
|
|
for _, p := range pac.subPackets {
|
|
|
|
i += countVersions(p)
|
2021-12-20 22:52:18 +00:00
|
|
|
}
|
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
|
|
|
func partOne() {
|
|
|
|
scanner := makeScanner(false)
|
|
|
|
|
|
|
|
scanner.Scan()
|
|
|
|
line := scanner.Text()
|
|
|
|
stream := []uint8{}
|
|
|
|
for _, hex := range line {
|
|
|
|
stream = append(stream, hexMap[hex]...)
|
|
|
|
}
|
|
|
|
_, parsedPacket := parsePackets(stream)
|
|
|
|
fmt.Println(countVersions(parsedPacket))
|
|
|
|
}
|
|
|
|
|
|
|
|
func partTwo() {
|
|
|
|
scanner := makeScanner(false)
|
|
|
|
|
|
|
|
for scanner.Scan() {
|
|
|
|
// line := scanner.Text()
|
|
|
|
}
|
|
|
|
}
|