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) int { result := int(0) for i := 0; i < length; i++ { result += int(stream[i]) << (length - 1 - i) } return result } type packet struct { version int typeID int subPackets []packet encodedNumber int } func getPacketVersion(stream []uint8) int { return parseNumber(stream, 3) } func getPacketType(stream []uint8) int { return parseNumber(stream, 3) } func getSubpacketLength(t uint8, stream []uint8) (int, int) { if t == 0 { return 15, parseNumber(stream, 15) } if t == 1 { return 11, parseNumber(stream, 11) } return 0, 0 } func parsePayload(stream []uint8) (int, 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, parsedPacket // 6 is packet header length } else { parsed := 0 size, subpacketlength := getSubpacketLength(stream[6], stream[7:]) for { consumed, subs := parsePackets(stream[7+size+parsed:]) if consumed == 0 { return parsed + 7 + size, parsedPacket } parsedPacket.subPackets = append(parsedPacket.subPackets, subs) parsed += consumed if size == 11 && len(parsedPacket.subPackets) == subpacketlength { return parsed + 7 + size, parsedPacket } else if size == 15 && parsed > subpacketlength { return parsed + 7 + size, parsedPacket } } } } func countVersions(pac packet) int { i := int(pac.version) for _, p := range pac.subPackets { i += countVersions(p) } 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 solve(p packet) int { switch p.typeID { case 0: // sum if len(p.subPackets) == 1 { return solve(p.subPackets[0]) } else { acc := 0 for _, v := range p.subPackets { acc += solve(v) } return acc } case 1: // product if len(p.subPackets) == 1 { return solve(p.subPackets[0]) } else { acc := solve(p.subPackets[0]) for _, v := range p.subPackets[1:] { acc *= solve(v) } return acc } case 2: // min if len(p.subPackets) == 1 { return solve(p.subPackets[0]) } else { acc := solve(p.subPackets[0]) for _, v := range p.subPackets[1:] { t := solve(v) if t < acc { acc = t } } return acc } case 3: // max if len(p.subPackets) == 1 { return solve(p.subPackets[0]) } else { acc := solve(p.subPackets[0]) for _, v := range p.subPackets[1:] { t := solve(v) if t > acc { acc = t } } return acc } case 4: // number return p.encodedNumber case 5: // > if len(p.subPackets) != 2 { panic(fmt.Sprintf("recevied type 5 packet with %d subpackets", len(p.subPackets))) } if solve(p.subPackets[0]) > solve(p.subPackets[1]) { return 1 } else { return 0 } case 6: // < if len(p.subPackets) != 2 { panic(fmt.Sprintf("recevied type 6 packet with %d subpackets", len(p.subPackets))) } if solve(p.subPackets[0]) < solve(p.subPackets[1]) { return 1 } else { return 0 } case 7: // == if len(p.subPackets) != 2 { panic(fmt.Sprintf("recevied type 7 packet with %d subpackets", len(p.subPackets))) } if solve(p.subPackets[0]) == solve(p.subPackets[1]) { return 1 } else { return 0 } default: panic("unknown packet type") } } func partTwo() { scanner := makeScanner(false) scanner.Scan() line := scanner.Text() stream := []uint8{} for _, hex := range line { stream = append(stream, hexMap[hex]...) } _, parsedPacket := parsePackets(stream) fmt.Println(solve(parsedPacket)) }