2021 Day 16 Complete
This commit is contained in:
240
2021/day16/main.go
Normal file
240
2021/day16/main.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||||
)
|
||||
|
||||
func main() {
|
||||
inp := h.StdinToString()
|
||||
var arg string
|
||||
if len(os.Args) > 1 {
|
||||
arg = os.Args[1]
|
||||
}
|
||||
|
||||
p := ParsePacket(inp)
|
||||
if arg == "--json" {
|
||||
fmt.Println(p.Json())
|
||||
} else {
|
||||
fmt.Println("# Part 1")
|
||||
fmt.Println("Version Sum:", CalculateVersionSum(p))
|
||||
fmt.Println()
|
||||
fmt.Println("# Part 2")
|
||||
fmt.Println("Value:", p.value)
|
||||
}
|
||||
}
|
||||
|
||||
func CalculateVersionSum(p *Packet) int {
|
||||
sum := p.version
|
||||
for s := range p.packets {
|
||||
sum += CalculateVersionSum(p.packets[s])
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
const (
|
||||
PacketTypeSum = iota
|
||||
PacketTypeProduct
|
||||
PacketTypeMin
|
||||
PacketTypeMax
|
||||
PacketTypeLiteral
|
||||
PacketTypeGreater
|
||||
PacketTypeLess
|
||||
PacketTypeEqual
|
||||
|
||||
LengthTypeBits = 0
|
||||
LengthTypeSubPackets = 1
|
||||
)
|
||||
|
||||
type Packet struct {
|
||||
version int
|
||||
packetType int
|
||||
|
||||
value int
|
||||
|
||||
// Operator
|
||||
lengthTypeId int
|
||||
subLength int
|
||||
|
||||
// Sub-packets
|
||||
packets []*Packet
|
||||
|
||||
binaryString string
|
||||
}
|
||||
|
||||
func ParsePacket(inp string) *Packet {
|
||||
var bin string
|
||||
for i := 0; i < len(inp); i += 2 {
|
||||
if len(inp) >= i+2 {
|
||||
bin += fmt.Sprintf("%08b", HexToByte(inp[i:i+2]))
|
||||
}
|
||||
}
|
||||
return ParseBinaryPacket(bin)
|
||||
}
|
||||
|
||||
func ParseBinaryPacket(inp string) *Packet {
|
||||
p := Packet{
|
||||
binaryString: inp,
|
||||
}
|
||||
// Parse the version
|
||||
for i := 0; i < 3; i++ {
|
||||
p.version = p.version << 1
|
||||
if p.binaryString[i] == '1' {
|
||||
p.version |= 1
|
||||
}
|
||||
}
|
||||
for i := 3; i < 6; i++ {
|
||||
p.packetType = p.packetType << 1
|
||||
if p.binaryString[i] == '1' {
|
||||
p.packetType |= 1
|
||||
}
|
||||
}
|
||||
if p.packetType == PacketTypeLiteral {
|
||||
p.parseLiteral()
|
||||
} else {
|
||||
p.parseOperator()
|
||||
}
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *Packet) parseLiteral() {
|
||||
// The bits for the literal start at bit 7
|
||||
// Every 5 bits is a chunk of the literal
|
||||
ptr := 6
|
||||
more := true
|
||||
for more {
|
||||
more = (p.binaryString[ptr] == '1')
|
||||
ptr++
|
||||
for i := 0; i < 4; i++ {
|
||||
p.value = p.value << 1
|
||||
if p.binaryString[ptr] == '1' {
|
||||
p.value |= 1
|
||||
}
|
||||
ptr++
|
||||
}
|
||||
}
|
||||
p.binaryString = p.binaryString[:ptr]
|
||||
}
|
||||
|
||||
func (p *Packet) parseOperator() {
|
||||
ptr := 6
|
||||
p.lengthTypeId = int(p.binaryString[ptr] - '0')
|
||||
ptr++
|
||||
if p.lengthTypeId == LengthTypeBits {
|
||||
for i := 0; i < 15; i++ {
|
||||
p.subLength = p.subLength << 1
|
||||
if p.binaryString[ptr] == '1' {
|
||||
p.subLength |= 1
|
||||
}
|
||||
ptr++
|
||||
}
|
||||
length := p.subLength
|
||||
for length > 0 {
|
||||
sp := ParseBinaryPacket(p.binaryString[ptr:])
|
||||
p.packets = append(p.packets, sp)
|
||||
ptr += len(sp.binaryString)
|
||||
length -= len(sp.binaryString)
|
||||
}
|
||||
p.binaryString = p.binaryString[:ptr]
|
||||
} else if p.lengthTypeId == LengthTypeSubPackets {
|
||||
for i := 0; i < 11; i++ {
|
||||
p.subLength = p.subLength << 1
|
||||
if p.binaryString[ptr] == '1' {
|
||||
p.subLength |= 1
|
||||
}
|
||||
ptr++
|
||||
}
|
||||
length := p.subLength
|
||||
for length > 0 {
|
||||
sp := ParseBinaryPacket(p.binaryString[ptr:])
|
||||
p.packets = append(p.packets, sp)
|
||||
ptr += len(sp.binaryString)
|
||||
length--
|
||||
}
|
||||
p.binaryString = p.binaryString[:ptr]
|
||||
}
|
||||
switch p.packetType {
|
||||
case PacketTypeSum:
|
||||
for _, sp := range p.packets {
|
||||
p.value += sp.value
|
||||
}
|
||||
case PacketTypeProduct:
|
||||
p.value = 1
|
||||
for _, sp := range p.packets {
|
||||
p.value *= sp.value
|
||||
}
|
||||
case PacketTypeMin:
|
||||
p.value = h.MAX_INT
|
||||
for _, sp := range p.packets {
|
||||
if sp.value < p.value {
|
||||
p.value = sp.value
|
||||
}
|
||||
}
|
||||
case PacketTypeMax:
|
||||
p.value = h.MIN_INT
|
||||
for _, sp := range p.packets {
|
||||
if sp.value > p.value {
|
||||
p.value = sp.value
|
||||
}
|
||||
}
|
||||
case PacketTypeGreater:
|
||||
if len(p.packets) == 2 && (p.packets[0].value > p.packets[1].value) {
|
||||
p.value = 1
|
||||
} else {
|
||||
p.value = 0
|
||||
}
|
||||
case PacketTypeLess:
|
||||
if len(p.packets) == 2 && (p.packets[0].value < p.packets[1].value) {
|
||||
p.value = 1
|
||||
} else {
|
||||
p.value = 0
|
||||
}
|
||||
case PacketTypeEqual:
|
||||
if len(p.packets) == 2 && (p.packets[0].value == p.packets[1].value) {
|
||||
p.value = 1
|
||||
} else {
|
||||
p.value = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p Packet) Json() string {
|
||||
ret := fmt.Sprintf("{\"version\":%d, \"type\":%d, \"value\":%d,", p.version, p.packetType, p.value)
|
||||
ret += "\"packets\":["
|
||||
for i := range p.packets {
|
||||
ret += fmt.Sprintf("%s", p.packets[i].String())
|
||||
if i < len(p.packets)-1 {
|
||||
ret += ","
|
||||
}
|
||||
}
|
||||
ret += fmt.Sprintf("],\"binary\":\"%s\"}", p.binaryString)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p Packet) String() string {
|
||||
if p.packetType == PacketTypeLiteral {
|
||||
return fmt.Sprintf("%d", p.value)
|
||||
} else {
|
||||
return p.Json()
|
||||
}
|
||||
}
|
||||
|
||||
func HexToByte(h string) byte {
|
||||
var b byte
|
||||
for i := range h {
|
||||
var wrk byte
|
||||
if h[i] >= '0' && h[i] <= '9' {
|
||||
wrk = byte(h[i] - '0')
|
||||
} else if h[i] >= 'A' && h[i] <= 'F' {
|
||||
wrk = byte(h[i]-'A') + 10
|
||||
}
|
||||
if i == 0 {
|
||||
b = wrk << 4
|
||||
} else {
|
||||
b |= wrk
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
Reference in New Issue
Block a user