package main
import (
"bufio"
"log"
"os"
"strconv"
"strings"
)
type packet struct {
version uint8
typeID uint8
number uint64
}
type BITS struct {
packets []packet
}
func main() {
if err := myMain(); err != nil {
log.Println(err)
}
}
func myMain() error {
in, err := parseInput("input.txt")
if err != nil {
return err
}
log.Println(solveFirst(in))
return nil
}
func solveFirst(in []string) int {
var sum int
for _, st := range in {
b := parseBITS(st)
sum = 0
for _, p := range b.packets {
sum += int(p.version)
}
// log.Println(sum)
}
return sum
}
func parseBITS(in string) BITS {
b := BITS{}
for len(in) >= len("VVVTTTAAAAA") {
in = b.parsePacket(in)
}
return b
}
func (b *BITS) parsePacket(in string) string {
// log.Println("parsePacket:", in)
p := packet{}
temp, err := strconv.ParseUint(in[0:3], 2, 8)
if err != nil {
panic(err)
}
p.version = uint8(temp)
temp, err = strconv.ParseUint(in[3:6], 2, 8)
if err != nil {
panic(err)
}
p.typeID = uint8(temp)
if p.typeID == 4 {
p.number, in = parseLiteral(in[6:])
} else {
in = b.parseOperator(in[6:])
}
b.packets = append(b.packets, p)
return in
}
func (b *BITS) parseOperator(in string) string {
// log.Println("parseOperator:", in)
lengthTypeID, err := strconv.ParseUint(in[:1], 2, 8)
if err != nil {
panic(err)
}
switch lengthTypeID {
case 0:
// total, err := strconv.ParseUint(in[1:16], 2, 64)
// if err != nil {
// panic(err)
// }
// log.Println("total length of subpackets:", total)
in = b.parsePacket(in[16:])
case 1:
// log.Println("subpackets:", in[1:12])
// subpackets, err := strconv.ParseInt(in[1:12], 2, 8)
// if err != nil {
// panic(err)
// }
// log.Println("numer of subpackets", subpackets)
in = b.parsePacket(in[12:])
default:
panic("invalid lengthTypeID")
}
return in
}
func parseLiteral(in string) (uint64, string) {
// log.Println("parseLiteral:", in)
tmp := strings.Builder{}
for i := 0; i < len(in); {
tmp.WriteString(in[i+1 : i+5])
if in[i] == '0' {
in = in[i+5:]
break
}
i += 5
}
temp, err := strconv.ParseUint(tmp.String(), 2, 64)
if err != nil {
panic(err)
}
return temp, in
}
func parseInput(fileName string) ([]string, error) {
ret := []string{}
fd, err := os.Open(fileName)
if err != nil {
return ret, err
}
defer fd.Close()
hexToBin := map[rune]string{
'0': "0000",
'1': "0001",
'2': "0010",
'3': "0011",
'4': "0100",
'5': "0101",
'6': "0110",
'7': "0111",
'8': "1000",
'9': "1001",
'A': "1010",
'B': "1011",
'C': "1100",
'D': "1101",
'E': "1110",
'F': "1111",
}
buf := bufio.NewScanner(fd)
for buf.Scan() {
tmp := strings.Builder{}
for _, ch := range buf.Text() {
tmp.WriteString(hexToBin[ch])
}
ret = append(ret, tmp.String())
}
return ret, nil
}