AdventOfCode2021/16/main.go

244 lines
4.9 KiB
Go

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))
}