173 lines
3.9 KiB
Go
173 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type packageStruct struct {
|
|
version int64
|
|
typeID int64
|
|
operator string
|
|
value int64
|
|
subPackages []packageStruct
|
|
}
|
|
|
|
func main() {
|
|
args := os.Args[1:]
|
|
input := args[0]
|
|
binaryNumberString := parseHexToBit(input)
|
|
pack, _ := parsePackage(binaryNumberString)
|
|
fmt.Println(pack)
|
|
sum := int64(0)
|
|
sumVers(pack, &sum)
|
|
fmt.Println(sum)
|
|
fmt.Println(calculatePart2(pack))
|
|
}
|
|
|
|
func calculatePart2(pack packageStruct) int64 {
|
|
switch pack.typeID {
|
|
case 0:
|
|
sum := int64(0)
|
|
for _, p := range pack.subPackages {
|
|
sum += calculatePart2(p)
|
|
}
|
|
return sum
|
|
case 1:
|
|
sum := int64(1)
|
|
for _, p := range pack.subPackages {
|
|
sum *= calculatePart2(p)
|
|
}
|
|
return sum
|
|
case 2:
|
|
min := calculatePart2(pack.subPackages[0])
|
|
for _, p := range pack.subPackages {
|
|
valueOfSubPackage := calculatePart2(p)
|
|
if min > valueOfSubPackage {
|
|
min = valueOfSubPackage
|
|
}
|
|
}
|
|
return min
|
|
case 3:
|
|
max := calculatePart2(pack.subPackages[0])
|
|
for _, p := range pack.subPackages {
|
|
valueOfSubPackage := calculatePart2(p)
|
|
if max < valueOfSubPackage {
|
|
max = valueOfSubPackage
|
|
}
|
|
}
|
|
return max
|
|
case 5:
|
|
if calculatePart2(pack.subPackages[0]) > calculatePart2(pack.subPackages[1]) {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
case 6:
|
|
if calculatePart2(pack.subPackages[0]) < calculatePart2(pack.subPackages[1]) {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
case 7:
|
|
if calculatePart2(pack.subPackages[0]) == calculatePart2(pack.subPackages[1]) {
|
|
return 1
|
|
} else {
|
|
return 0
|
|
}
|
|
default:
|
|
return pack.value
|
|
}
|
|
}
|
|
|
|
func sumVers(pack packageStruct, sum *int64) {
|
|
*sum += pack.version
|
|
for _, p := range pack.subPackages {
|
|
sumVers(p, sum)
|
|
}
|
|
}
|
|
|
|
func parseHexToBit(hex string) string {
|
|
returnString := ""
|
|
for _, char := range hex {
|
|
number, _ := strconv.ParseInt(string(char), 16, 0)
|
|
returnString += padBinaryNumber(strconv.FormatInt(number, 2))
|
|
}
|
|
return returnString
|
|
}
|
|
|
|
func padBinaryNumber(binaryNumberString string) string {
|
|
if (len(binaryNumberString) % 4) > 0 {
|
|
amountPaddingZeros := 4 - (len(binaryNumberString) % 4)
|
|
binaryNumberString = strings.Repeat("0", amountPaddingZeros) + binaryNumberString
|
|
}
|
|
return binaryNumberString
|
|
}
|
|
|
|
func parsePackage(binaryNumberString string) (pack packageStruct, index int64) {
|
|
index = 0
|
|
pack.version, _ = strconv.ParseInt(binaryNumberString[:3], 2, 0)
|
|
pack.typeID, _ = strconv.ParseInt(binaryNumberString[3:6], 2, 0)
|
|
index += 6
|
|
if pack.typeID == 4 {
|
|
indexAdd := int64(0)
|
|
pack.value, indexAdd = parseLiteralValue(binaryNumberString[6:])
|
|
index += indexAdd
|
|
return
|
|
}
|
|
subPackages, indexAdd := parseOperator(binaryNumberString[6:])
|
|
pack.subPackages = subPackages
|
|
index += indexAdd
|
|
return
|
|
}
|
|
|
|
func parseLiteralValue(packageString string) (value int64, index int64) {
|
|
index = 0
|
|
number := ""
|
|
for {
|
|
number += packageString[index+1 : index+5]
|
|
if packageString[index] == '0' {
|
|
value, _ = strconv.ParseInt(number, 2, 0)
|
|
index += 5
|
|
return
|
|
}
|
|
index += 5
|
|
}
|
|
}
|
|
|
|
func parseOperator(packageString string) (packs []packageStruct, index int64) {
|
|
index = 1
|
|
lengthTypeID := packageString[0]
|
|
if lengthTypeID == '0' {
|
|
lengthSubPackets, _ := strconv.ParseInt(packageString[index+1:index+15], 2, 0)
|
|
index += 15
|
|
subPackageBinary := packageString[index : index+lengthSubPackets]
|
|
subPackageIndex := int64(0)
|
|
for subPackageIndex < lengthSubPackets {
|
|
pack, i := parsePackage(subPackageBinary[subPackageIndex:])
|
|
packs = append(packs, pack)
|
|
subPackageIndex += i
|
|
}
|
|
index += lengthSubPackets
|
|
return
|
|
}
|
|
if lengthTypeID == '1' {
|
|
neededSubPackets, _ := strconv.ParseInt(packageString[index+1:index+11], 2, 0)
|
|
index += 11
|
|
subPackageBinary := packageString[index:]
|
|
subPackageIndex := int64(0)
|
|
countSubPackets := int64(0)
|
|
for countSubPackets < neededSubPackets {
|
|
pack, i := parsePackage(subPackageBinary[subPackageIndex:])
|
|
packs = append(packs, pack)
|
|
subPackageIndex += i
|
|
countSubPackets++
|
|
}
|
|
index += subPackageIndex
|
|
return
|
|
}
|
|
return
|
|
}
|