day 16 part one finally
This commit is contained in:
parent
0f07ffcc00
commit
44c8a7659d
154
16/main.go
Normal file
154
16/main.go
Normal file
@ -0,0 +1,154 @@
|
||||
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()
|
||||
}
|
||||
}
|
61
16/main_test.go
Normal file
61
16/main_test.go
Normal file
@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVersionParse(t *testing.T) {
|
||||
tests := map[int64][]uint8{
|
||||
0: {0, 0, 0},
|
||||
1: {0, 0, 1},
|
||||
2: {0, 1, 0},
|
||||
3: {0, 1, 1},
|
||||
4: {1, 0, 0},
|
||||
5: {1, 0, 1},
|
||||
6: {1, 1, 0},
|
||||
7: {1, 1, 1},
|
||||
}
|
||||
for result, input := range tests {
|
||||
if result != getPacketVersion(input) {
|
||||
t.Fail()
|
||||
}
|
||||
if result != getPacketType(input) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePayload(t *testing.T) {
|
||||
if n, q := parsePayload([]uint8{0, 1, 0, 1, 0}); n != 10 || q != 5 {
|
||||
t.Log(n, q)
|
||||
t.Fail()
|
||||
}
|
||||
if n, q := parsePayload([]uint8{1, 0, 0, 0, 1, 0, 0, 1, 0, 0}); n != 20 || q != 10 {
|
||||
t.Log(n, q)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCases(t *testing.T) {
|
||||
inputs := map[string]int{
|
||||
"D2FE28": 6,
|
||||
"38006F45291200": 9,
|
||||
"EE00D40C823060": 14,
|
||||
"8A004A801A8002F478": 16,
|
||||
"620080001611562C8802118E34": 12,
|
||||
"C0015000016115A2E0802F182340": 23,
|
||||
"A0016C880162017C3686B18A3D4780": 31,
|
||||
}
|
||||
|
||||
for c, r := range inputs {
|
||||
stream := []uint8{}
|
||||
for _, hex := range c {
|
||||
stream = append(stream, hexMap[hex]...)
|
||||
}
|
||||
_, parsedPacket := parsePackets(stream)
|
||||
if r != countVersions(parsedPacket) {
|
||||
t.Log(c, countVersions(parsedPacket))
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user