Day 16 first attempt. Not working yet
This commit is contained in:
227
sixteen/bits.go
Normal file
227
sixteen/bits.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package sixteen
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
literalType = 4
|
||||
lengthType15 = 0
|
||||
lengthType11 = 1
|
||||
)
|
||||
|
||||
var hexToBin = map[string]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",
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
packet string
|
||||
version int
|
||||
typeID int
|
||||
content int
|
||||
subpackets []packet
|
||||
}
|
||||
|
||||
func (p *packet) versionSum() int {
|
||||
sum := p.version
|
||||
|
||||
for _, s := range p.subpackets {
|
||||
sum += s.versionSum()
|
||||
}
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
func hexToBinary(input string) string {
|
||||
output := ""
|
||||
for _, r := range input {
|
||||
output += hexToBin[string(r)]
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func parseHex(input string) packet {
|
||||
binary := hexToBinary(input)
|
||||
return parse(binary)
|
||||
}
|
||||
|
||||
func parse(input string) packet {
|
||||
b := packet{}
|
||||
b.packet = input
|
||||
|
||||
b.version, b.typeID = parseVersionType(input)
|
||||
content := input[6:]
|
||||
|
||||
switch b.typeID {
|
||||
case literalType:
|
||||
b.content, _ = parseLiteral(content)
|
||||
default:
|
||||
b.subpackets, _ = parseOperator(content)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
func parseVersionType(input string) (int, int) {
|
||||
var version, typeID string
|
||||
if count, err := fmt.Sscanf(input, "%3s%3s", &version, &typeID); count != 2 || err != nil {
|
||||
fmt.Println("Unable to parse", input, err)
|
||||
return -1, -1
|
||||
}
|
||||
|
||||
v, err := strconv.ParseInt(version, 2, 64)
|
||||
if err != nil {
|
||||
fmt.Println("Unable to parse version from", version, err)
|
||||
return -1, -1
|
||||
}
|
||||
|
||||
t, err := strconv.ParseInt(typeID, 2, 64)
|
||||
if err != nil {
|
||||
fmt.Println("Unable to parse type from", typeID, err)
|
||||
return -1, -1
|
||||
}
|
||||
|
||||
return int(v), int(t)
|
||||
}
|
||||
|
||||
func parsePackets(input string) []packet {
|
||||
packets := []packet{}
|
||||
|
||||
remaining := input
|
||||
for remaining != "" {
|
||||
version, typeID := parseVersionType(remaining)
|
||||
|
||||
p := packet{
|
||||
version: version,
|
||||
typeID: typeID,
|
||||
}
|
||||
|
||||
switch p.typeID {
|
||||
case literalType:
|
||||
value, length := parseLiteral(remaining[6:])
|
||||
p.content = value
|
||||
p.packet = remaining[:length+6]
|
||||
remaining = remaining[length+6:]
|
||||
default:
|
||||
l := 0
|
||||
p.subpackets, l = parseOperator(remaining[6:])
|
||||
remaining = remaining[l+7:]
|
||||
}
|
||||
|
||||
packets = append(packets, p)
|
||||
}
|
||||
|
||||
return packets
|
||||
}
|
||||
|
||||
func parseNPackets(input string, count int) ([]packet, int) {
|
||||
length := len(input)
|
||||
packets := []packet{}
|
||||
|
||||
remaining := input
|
||||
for len(packets) != count {
|
||||
version, typeID := parseVersionType(remaining)
|
||||
|
||||
p := packet{
|
||||
version: version,
|
||||
typeID: typeID,
|
||||
}
|
||||
|
||||
switch p.typeID {
|
||||
case literalType:
|
||||
value, length := parseLiteral(remaining[6:])
|
||||
p.content = value
|
||||
p.packet = remaining[:length+6]
|
||||
remaining = remaining[length+6:]
|
||||
default:
|
||||
l := 0
|
||||
p.subpackets, l = parseOperator(remaining[6:])
|
||||
remaining = remaining[l+7:]
|
||||
}
|
||||
|
||||
packets = append(packets, p)
|
||||
}
|
||||
|
||||
return packets, length - len(remaining)
|
||||
}
|
||||
|
||||
func parseOperator(input string) ([]packet, int) {
|
||||
length := 0
|
||||
subPackets := []packet{}
|
||||
var lType int
|
||||
var remainder string
|
||||
if count, err := fmt.Sscanf(input, "%1d%s", &lType, &remainder); count != 2 || err != nil {
|
||||
fmt.Println("Unable to parse operator type", input)
|
||||
return subPackets, length
|
||||
}
|
||||
|
||||
switch lType {
|
||||
case lengthType15:
|
||||
lengthBits, _ := strconv.ParseInt(string(remainder[:15]), 2, 64)
|
||||
subs := parsePackets(remainder[15 : 15+lengthBits])
|
||||
subPackets = append(subPackets, subs...)
|
||||
length = 15 + int(lengthBits)
|
||||
case lengthType11:
|
||||
lengthBits, _ := strconv.ParseInt(string(remainder[:11]), 2, 64)
|
||||
subs, l := parseNPackets(remainder[11:], int(lengthBits))
|
||||
subPackets = append(subPackets, subs...)
|
||||
length = l
|
||||
}
|
||||
|
||||
return subPackets, length
|
||||
}
|
||||
|
||||
func parseLiteral(input string) (int, int) {
|
||||
literal := ""
|
||||
length := 0
|
||||
for i := 0; i < len(input); i += 5 {
|
||||
literal += string(input[i+1]) + string(input[i+2]) + string(input[i+3]) + string(input[i+4])
|
||||
length += 5
|
||||
|
||||
if input[i] == '0' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
v, err := strconv.ParseInt(literal, 2, 64)
|
||||
if err != nil {
|
||||
fmt.Println("Unable to parse", literal, err)
|
||||
return 0, -1
|
||||
}
|
||||
|
||||
return int(v), length
|
||||
}
|
||||
|
||||
func load(filename string) packet {
|
||||
b := packet{}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return b
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
b = parseHex(scanner.Text())
|
||||
}
|
||||
return b
|
||||
}
|
Reference in New Issue
Block a user