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 } func parsePackets(stream []uint8) (int, []packet) { if len(stream) <= 7 { return 0, []packet{} } 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 return consumed + 6, []packet{parsedPacket} // 6 is packet header length } else { parsed := 0 size, subpacketlength := getSubpacketLength(stream[6], stream[7:]) for { consumed, subs := parsePackets(stream[7+size+parsed:]) parsedPacket.subPackets = append(parsedPacket.subPackets, subs...) parsed += consumed if size == 11 && int64(len(parsedPacket.subPackets)) == subpacketlength { return parsed + 7 + size, []packet{parsedPacket} } else if size == 15 && int64(parsed) > subpacketlength || consumed == 0 { return parsed + 7 + size, []packet{parsedPacket} } } } } func countVersions(packets []packet) int { i := 0 for _, p := range packets { i += int(p.version) i += countVersions(p.subPackets) } 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() } }