From 0581fb389c2e2aae2f5fe920da2982191c274b22 Mon Sep 17 00:00:00 2001 From: Russell Champoux Date: Tue, 28 Dec 2021 09:55:06 -0500 Subject: [PATCH] day 16 work --- day-16/main.go | 158 ++++++++++++++++++++++++++++++++++++++++------- utils/log/log.go | 2 +- 2 files changed, 136 insertions(+), 24 deletions(-) diff --git a/day-16/main.go b/day-16/main.go index ff0799a..cdf5203 100644 --- a/day-16/main.go +++ b/day-16/main.go @@ -7,12 +7,12 @@ import ( "AoC2021/utils/color" "AoC2021/utils/files" "AoC2021/utils/log" + "AoC2021/utils/numbers" "AoC2021/utils/timer" "bufio" "fmt" "math" "os" - "strings" ) func check(e error) { @@ -70,8 +70,24 @@ func part1() { func part2() { log.Println(log.NORMAL, "* Part 2 *") - log.Println(log.NORMAL, " Goal: ") - log.Println(log.NORMAL, " Answer: ") + log.Println(log.NORMAL, " Goal: Do the same thing but perform operations and stuff") + 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() { @@ -105,7 +121,6 @@ func parseInputFile() { type Packet struct { id int value int - subValues int version int subVersions int pType int @@ -114,11 +129,22 @@ type Packet struct { subBitCount int } +const ( + SUM = 0 + PRODUCT = 1 + MINIMUM = 2 + MAXIMUM = 3 + LITERAL = 4 + GREATERTHAN = 5 + LESSTHAN = 6 + EQUALTO = 7 +) + var packetNum = 0 func parsePacket(bitReader *BitReader, depth int) (Packet, error) { 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) p.bitCount += 3 if err != nil { @@ -132,12 +158,12 @@ func parsePacket(bitReader *BitReader, depth int) (Packet, error) { } p.pType = bits.ToInt(typeBits) - 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, "\nP: %3d %s", packetNum, strings.Repeat(" ", depth*2)) + // log.Printf(log.DIAGNOSTIC, "Ver %d, Type %d", p.version, p.pType) switch p.pType { - case 4: - log.Printf(log.DIAGNOSTIC, ": L") + case LITERAL: + // log.Printf(log.DIAGNOSTIC, ": L") var litBits []bool var bitVals []bool // 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 litBits = append(litBits, bitVals[1:]...) p.value = bits.ToInt(litBits) - log.Printf(log.DIAGNOSTIC, " (value %d)", p.value) + log.Printf(log.DIAGNOSTIC, "%d", p.value) return p, nil - default: - log.Printf(log.DIAGNOSTIC, ": O") + case SUM, PRODUCT, MINIMUM, MAXIMUM, GREATERTHAN, LESSTHAN, EQUALTO: + // log.Printf(log.DIAGNOSTIC, ": O") + log.Printf(log.DIAGNOSTIC, operString(p.pType)) hasSubpackets, err := bitReader.ReadBit() p.bitCount += 1 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()) } 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) - log.Printf(log.DIAGNOSTIC, " [S: %d]", subpacketTotal+1) + // log.Printf(log.DIAGNOSTIC, " [S: %d]", subpacketTotal+1) if err != nil { 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++ - p.subValues += sp.value + sp.subValues p.subVersions += sp.version + sp.subVersions p.subBitCount += sp.bitCount + sp.subBitCount + + if subpacketTotal < p.subpacketCount { + log.Printf(log.DIAGNOSTIC, ", ") + } } } else { 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()) } p.subBitCount = bits.ToInt(lengthBits) - log.Printf(log.DIAGNOSTIC, " (length: %d) {", p.subBitCount) + //log.Printf(log.DIAGNOSTIC, " (length: %d) {", p.subBitCount) subpacketBits := 0 - for subpacketBits < p.subBitCount { + for accum := getAccum(p.pType); subpacketBits < p.subBitCount; { 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 { 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 - p.subValues += sp.value + sp.subValues p.subVersions += sp.version + sp.subVersions p.subpacketCount += 1 + sp.subpacketCount + + if subpacketBits < p.subBitCount { + log.Printf(log.DIAGNOSTIC, ", ") + } } if subpacketBits != p.subBitCount { 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 { - log.Printf(log.DIAGNOSTIC, "\n%s}", strings.Repeat(" ", 6+depth*2)) - } + // if p.pType != 4 { + // log.Printf(log.DIAGNOSTIC, "\n%s}", strings.Repeat(" ", 6+depth*2)) + // } 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 { file *os.File values []bool diff --git a/utils/log/log.go b/utils/log/log.go index 5f1a926..c30781f 100644 --- a/utils/log/log.go +++ b/utils/log/log.go @@ -30,7 +30,7 @@ func SetLogLevel(level int) { func SetLogLevelFromArgs(argMap map[string]string) { logLevelStr, found := argMap["log"] - if found { + if found && logLevelStr != "" { logLevel, err := NORMAL, error(nil) switch logLevelStr {