mirror of
https://github.com/RussellChamp/advent-of-code-2021.git
synced 2026-10-27 21:52:32 +00:00
day 16 work
This commit is contained in:
1 parent
3845c2a457
commit
0581fb389c
2 files changed
+136
-24
No files matched your search
+135
-23
@@ -7,12 +7,12 @@ import (
|
|||||||
"AoC2021/utils/color"
|
"AoC2021/utils/color"
|
||||||
"AoC2021/utils/files"
|
"AoC2021/utils/files"
|
||||||
"AoC2021/utils/log"
|
"AoC2021/utils/log"
|
||||||
|
"AoC2021/utils/numbers"
|
||||||
"AoC2021/utils/timer"
|
"AoC2021/utils/timer"
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func check(e error) {
|
func check(e error) {
|
||||||
@@ -70,8 +70,24 @@ func part1() {
|
|||||||
|
|
||||||
func part2() {
|
func part2() {
|
||||||
log.Println(log.NORMAL, "* Part 2 *")
|
log.Println(log.NORMAL, "* Part 2 *")
|
||||||
log.Println(log.NORMAL, " Goal: ")
|
log.Println(log.NORMAL, " Goal: Do the same thing but perform operations and stuff")
|
||||||
log.Println(log.NORMAL, " Answer: ")
|
log.Println(log.NORMAL, " Answer: What do you get if you evaluate the expression represented by your hexadecimal-encoded BITS transmission?")
|
||||||
|
|
||||||
|
input, err := os.Open("./input.txt")
|
||||||
|
check(err)
|
||||||
|
defer input.Close()
|
||||||
|
|
||||||
|
bitReader := NewBitReader(input)
|
||||||
|
p, err := parsePacket(&bitReader, 0)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(bitReader.file)
|
||||||
|
if scanner.Scan() {
|
||||||
|
bytesLeft := len(scanner.Bytes())
|
||||||
|
log.Printf(log.NORMAL, color.Yellow+"\nCompleted reading from file with %d bytes remaining!\n"+color.Reset, bytesLeft)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf(log.NORMAL, "\nTotal of all versions is %d\n", p.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseInputFile() {
|
func parseInputFile() {
|
||||||
@@ -105,7 +121,6 @@ func parseInputFile() {
|
|||||||
type Packet struct {
|
type Packet struct {
|
||||||
id int
|
id int
|
||||||
value int
|
value int
|
||||||
subValues int
|
|
||||||
version int
|
version int
|
||||||
subVersions int
|
subVersions int
|
||||||
pType int
|
pType int
|
||||||
@@ -114,11 +129,22 @@ type Packet struct {
|
|||||||
subBitCount int
|
subBitCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SUM = 0
|
||||||
|
PRODUCT = 1
|
||||||
|
MINIMUM = 2
|
||||||
|
MAXIMUM = 3
|
||||||
|
LITERAL = 4
|
||||||
|
GREATERTHAN = 5
|
||||||
|
LESSTHAN = 6
|
||||||
|
EQUALTO = 7
|
||||||
|
)
|
||||||
|
|
||||||
var packetNum = 0
|
var packetNum = 0
|
||||||
|
|
||||||
func parsePacket(bitReader *BitReader, depth int) (Packet, error) {
|
func parsePacket(bitReader *BitReader, depth int) (Packet, error) {
|
||||||
packetNum++
|
packetNum++
|
||||||
p := Packet{packetNum, 0, 0, 0, 0, 0, 0, 0, 0}
|
p := Packet{packetNum, 0, 0, 0, 0, 0, 0, 0}
|
||||||
versionBits, err := bitReader.ReadBits(3)
|
versionBits, err := bitReader.ReadBits(3)
|
||||||
p.bitCount += 3
|
p.bitCount += 3
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -132,12 +158,12 @@ func parsePacket(bitReader *BitReader, depth int) (Packet, error) {
|
|||||||
}
|
}
|
||||||
p.pType = bits.ToInt(typeBits)
|
p.pType = bits.ToInt(typeBits)
|
||||||
|
|
||||||
log.Printf(log.DIAGNOSTIC, "\nP: %3d %s", packetNum, strings.Repeat(" ", depth*2))
|
// log.Printf(log.DIAGNOSTIC, "\nP: %3d %s", packetNum, strings.Repeat(" ", depth*2))
|
||||||
log.Printf(log.DIAGNOSTIC, "Ver %d, Type %d", p.version, p.pType)
|
// log.Printf(log.DIAGNOSTIC, "Ver %d, Type %d", p.version, p.pType)
|
||||||
|
|
||||||
switch p.pType {
|
switch p.pType {
|
||||||
case 4:
|
case LITERAL:
|
||||||
log.Printf(log.DIAGNOSTIC, ": L")
|
// log.Printf(log.DIAGNOSTIC, ": L")
|
||||||
var litBits []bool
|
var litBits []bool
|
||||||
var bitVals []bool
|
var bitVals []bool
|
||||||
// read sets of 5 bits until the first bit of 5 is not a '1'
|
// read sets of 5 bits until the first bit of 5 is not a '1'
|
||||||
@@ -152,11 +178,12 @@ func parsePacket(bitReader *BitReader, depth int) (Packet, error) {
|
|||||||
p.bitCount += 5
|
p.bitCount += 5
|
||||||
litBits = append(litBits, bitVals[1:]...)
|
litBits = append(litBits, bitVals[1:]...)
|
||||||
p.value = bits.ToInt(litBits)
|
p.value = bits.ToInt(litBits)
|
||||||
log.Printf(log.DIAGNOSTIC, " (value %d)", p.value)
|
log.Printf(log.DIAGNOSTIC, "%d", p.value)
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
default:
|
case SUM, PRODUCT, MINIMUM, MAXIMUM, GREATERTHAN, LESSTHAN, EQUALTO:
|
||||||
log.Printf(log.DIAGNOSTIC, ": O")
|
// log.Printf(log.DIAGNOSTIC, ": O")
|
||||||
|
log.Printf(log.DIAGNOSTIC, operString(p.pType))
|
||||||
hasSubpackets, err := bitReader.ReadBit()
|
hasSubpackets, err := bitReader.ReadBit()
|
||||||
p.bitCount += 1
|
p.bitCount += 1
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -169,18 +196,28 @@ func parsePacket(bitReader *BitReader, depth int) (Packet, error) {
|
|||||||
return p, fmt.Errorf("%s for subpacket count", err.Error())
|
return p, fmt.Errorf("%s for subpacket count", err.Error())
|
||||||
}
|
}
|
||||||
p.subpacketCount = bits.ToInt(countBits)
|
p.subpacketCount = bits.ToInt(countBits)
|
||||||
log.Printf(log.DIAGNOSTIC, " (count: %d) {", p.subpacketCount)
|
// log.Printf(log.DIAGNOSTIC, " (count: %d) {", p.subpacketCount)
|
||||||
|
|
||||||
for subpacketTotal := 0; subpacketTotal < p.subpacketCount; {
|
for subpacketTotal, accum := 0, getAccum(p.pType); subpacketTotal < p.subpacketCount; {
|
||||||
sp, err := parsePacket(bitReader, depth+1)
|
sp, err := parsePacket(bitReader, depth+1)
|
||||||
log.Printf(log.DIAGNOSTIC, " [S: %d]", subpacketTotal+1)
|
// log.Printf(log.DIAGNOSTIC, " [S: %d]", subpacketTotal+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return p, fmt.Errorf("%s for subpacket %d of id#%d", err.Error(), subpacketTotal+1, p.id)
|
return p, fmt.Errorf("%s for subpacket %d of id#%d", err.Error(), subpacketTotal+1, p.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if subpacketTotal == 0 && (p.pType == GREATERTHAN || p.pType == LESSTHAN || p.pType == EQUALTO) {
|
||||||
|
accum = sp.value
|
||||||
|
} else {
|
||||||
|
p.value = mungeValue(accum, p.pType, sp.value)
|
||||||
|
}
|
||||||
|
|
||||||
subpacketTotal++
|
subpacketTotal++
|
||||||
p.subValues += sp.value + sp.subValues
|
|
||||||
p.subVersions += sp.version + sp.subVersions
|
p.subVersions += sp.version + sp.subVersions
|
||||||
p.subBitCount += sp.bitCount + sp.subBitCount
|
p.subBitCount += sp.bitCount + sp.subBitCount
|
||||||
|
|
||||||
|
if subpacketTotal < p.subpacketCount {
|
||||||
|
log.Printf(log.DIAGNOSTIC, ", ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lengthBits, err := bitReader.ReadBits(15)
|
lengthBits, err := bitReader.ReadBits(15)
|
||||||
@@ -189,31 +226,106 @@ func parsePacket(bitReader *BitReader, depth int) (Packet, error) {
|
|||||||
return p, fmt.Errorf("%s for subpacket length", err.Error())
|
return p, fmt.Errorf("%s for subpacket length", err.Error())
|
||||||
}
|
}
|
||||||
p.subBitCount = bits.ToInt(lengthBits)
|
p.subBitCount = bits.ToInt(lengthBits)
|
||||||
log.Printf(log.DIAGNOSTIC, " (length: %d) {", p.subBitCount)
|
//log.Printf(log.DIAGNOSTIC, " (length: %d) {", p.subBitCount)
|
||||||
subpacketBits := 0
|
subpacketBits := 0
|
||||||
for subpacketBits < p.subBitCount {
|
for accum := getAccum(p.pType); subpacketBits < p.subBitCount; {
|
||||||
sp, err := parsePacket(bitReader, depth+1)
|
sp, err := parsePacket(bitReader, depth+1)
|
||||||
log.Printf(log.DIAGNOSTIC, " [S: %d]", p.subpacketCount+1)
|
//log.Printf(log.DIAGNOSTIC, " [S: %d]", p.subpacketCount+1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return p, fmt.Errorf("%s for subpacket of id#%d", err.Error(), p.id)
|
return p, fmt.Errorf("%s for subpacket of id#%d", err.Error(), p.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if subpacketBits == 0 && (p.pType == GREATERTHAN || p.pType == LESSTHAN || p.pType == EQUALTO) {
|
||||||
|
accum = sp.value
|
||||||
|
} else {
|
||||||
|
p.value = mungeValue(accum, p.pType, sp.value)
|
||||||
|
}
|
||||||
|
|
||||||
subpacketBits += sp.bitCount + sp.subBitCount
|
subpacketBits += sp.bitCount + sp.subBitCount
|
||||||
p.subValues += sp.value + sp.subValues
|
|
||||||
p.subVersions += sp.version + sp.subVersions
|
p.subVersions += sp.version + sp.subVersions
|
||||||
p.subpacketCount += 1 + sp.subpacketCount
|
p.subpacketCount += 1 + sp.subpacketCount
|
||||||
|
|
||||||
|
if subpacketBits < p.subBitCount {
|
||||||
|
log.Printf(log.DIAGNOSTIC, ", ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if subpacketBits != p.subBitCount {
|
if subpacketBits != p.subBitCount {
|
||||||
return p, fmt.Errorf("packet #%d should parse %d bits but parsed %d", p.id, p.subBitCount, subpacketBits)
|
return p, fmt.Errorf("packet #%d should parse %d bits but parsed %d", p.id, p.subBitCount, subpacketBits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf(log.DIAGNOSTIC, ")")
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.pType != 4 {
|
// if p.pType != 4 {
|
||||||
log.Printf(log.DIAGNOSTIC, "\n%s}", strings.Repeat(" ", 6+depth*2))
|
// log.Printf(log.DIAGNOSTIC, "\n%s}", strings.Repeat(" ", 6+depth*2))
|
||||||
}
|
// }
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the starting accumulator for a given operation
|
||||||
|
func getAccum(oper int) int {
|
||||||
|
switch oper {
|
||||||
|
case SUM:
|
||||||
|
return 0
|
||||||
|
case PRODUCT:
|
||||||
|
return 1
|
||||||
|
case MINIMUM:
|
||||||
|
return -math.MaxInt
|
||||||
|
case MAXIMUM:
|
||||||
|
return math.MinInt
|
||||||
|
case GREATERTHAN:
|
||||||
|
return 1
|
||||||
|
case LESSTHAN:
|
||||||
|
return 1
|
||||||
|
case EQUALTO:
|
||||||
|
return 1
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Got invalid operation %d", oper))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform an operation on the given packet and return a new value
|
||||||
|
func mungeValue(oldVal, oper, newVal int) int {
|
||||||
|
switch oper {
|
||||||
|
case SUM:
|
||||||
|
return oldVal + newVal
|
||||||
|
case PRODUCT:
|
||||||
|
return oldVal * newVal
|
||||||
|
case MINIMUM:
|
||||||
|
return numbers.Min(oldVal, newVal)
|
||||||
|
case MAXIMUM:
|
||||||
|
return numbers.Max(oldVal, newVal)
|
||||||
|
case GREATERTHAN:
|
||||||
|
return numbers.BoolToInt(oldVal > newVal)
|
||||||
|
case LESSTHAN:
|
||||||
|
return numbers.BoolToInt(oldVal < newVal)
|
||||||
|
case EQUALTO:
|
||||||
|
return numbers.BoolToInt(oldVal == newVal)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Got invalid operation %d", oper))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func operString(oper int) string {
|
||||||
|
switch oper {
|
||||||
|
case SUM:
|
||||||
|
return "SUM("
|
||||||
|
case PRODUCT:
|
||||||
|
return "PROD("
|
||||||
|
case MINIMUM:
|
||||||
|
return "MIN("
|
||||||
|
case MAXIMUM:
|
||||||
|
return "MAX("
|
||||||
|
case GREATERTHAN:
|
||||||
|
return "GT("
|
||||||
|
case LESSTHAN:
|
||||||
|
return "LT("
|
||||||
|
case EQUALTO:
|
||||||
|
return "EQ("
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("Got invalid operation %d", oper))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type BitReader struct {
|
type BitReader struct {
|
||||||
file *os.File
|
file *os.File
|
||||||
values []bool
|
values []bool
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ func SetLogLevel(level int) {
|
|||||||
|
|
||||||
func SetLogLevelFromArgs(argMap map[string]string) {
|
func SetLogLevelFromArgs(argMap map[string]string) {
|
||||||
logLevelStr, found := argMap["log"]
|
logLevelStr, found := argMap["log"]
|
||||||
if found {
|
if found && logLevelStr != "" {
|
||||||
logLevel, err := NORMAL, error(nil)
|
logLevel, err := NORMAL, error(nil)
|
||||||
|
|
||||||
switch logLevelStr {
|
switch logLevelStr {
|
||||||
|
|||||||
Reference in new issue
Block a user