mirror of
https://github.com/RussellChamp/advent-of-code-2021.git
synced 2026-10-27 21:52:32 +00:00
day 16 part 1
This commit is contained in:
1 parent
4737afa383
commit
0c277a8404
11 files changed
+463
-1
No files matched your search
@@ -6,6 +6,14 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// func short_read() {
|
||||
// dat, err := os.Open("./short_file.txt")
|
||||
// tryMe(err)
|
||||
// defer dat.Close()
|
||||
|
||||
// bytes := ??
|
||||
// }
|
||||
|
||||
func tryMe(e error) {
|
||||
if e != nil {
|
||||
fmt.Println("OH SNAP!")
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
abcd
|
||||
Binary file not shown.
+268
@@ -0,0 +1,268 @@
|
||||
/* Day 16: Packet Decoder */
|
||||
package main
|
||||
|
||||
import (
|
||||
"AoC2021/utils/args"
|
||||
"AoC2021/utils/bits"
|
||||
"AoC2021/utils/color"
|
||||
"AoC2021/utils/files"
|
||||
"AoC2021/utils/log"
|
||||
"AoC2021/utils/timer"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
log.Println(log.DEBUG, "Oh snap!")
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
argMap := args.Parse(os.Args)
|
||||
log.SetLogLevelFromArgs(argMap)
|
||||
selectedPart, partSpecified := argMap["part"]
|
||||
|
||||
log.Println(log.NORMAL, "--- Day 16: Packet Decoder ---")
|
||||
timer.Start()
|
||||
|
||||
if selectedPart == "parse" {
|
||||
parseInputFile()
|
||||
}
|
||||
if !partSpecified || selectedPart == "1" {
|
||||
part1()
|
||||
timer.Tick()
|
||||
log.Println(log.NORMAL)
|
||||
}
|
||||
|
||||
if !partSpecified || selectedPart == "2" {
|
||||
part2()
|
||||
timer.Tick()
|
||||
log.Println(log.NORMAL)
|
||||
}
|
||||
}
|
||||
|
||||
func part1() {
|
||||
log.Println(log.NORMAL, "* Part 1 *")
|
||||
log.Println(log.NORMAL, " Goal: For now, parse the hierarchy of the packets throughout the transmission. Decode the structure of your hexadecimal-encoded BITS transmission")
|
||||
log.Println(log.NORMAL, " Answer: what do you get if you add up the version numbers in all packets?")
|
||||
|
||||
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+"Completed reading from file with %d bytes remaining!\n"+color.Reset, bytesLeft)
|
||||
}
|
||||
|
||||
log.Printf(log.NORMAL, "\nTotal of all versions is %d\n", p.version+p.subVersions)
|
||||
}
|
||||
|
||||
func part2() {
|
||||
log.Println(log.NORMAL, "* Part 2 *")
|
||||
log.Println(log.NORMAL, " Goal: ")
|
||||
log.Println(log.NORMAL, " Answer: ")
|
||||
}
|
||||
|
||||
func parseInputFile() {
|
||||
input, err := os.Open("./input.txt")
|
||||
check(err)
|
||||
defer input.Close()
|
||||
|
||||
output, err := files.CreateOrReplace("./output.txt")
|
||||
check(err)
|
||||
defer output.Close()
|
||||
|
||||
scanner := bufio.NewScanner(input)
|
||||
for scanner.Scan() {
|
||||
bytes := scanner.Bytes()
|
||||
for _, b := range bytes {
|
||||
outBits, err := bits.HexByteToBits(b)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Error parsing byte %s", string(b)))
|
||||
}
|
||||
for _, ob := range outBits {
|
||||
if ob {
|
||||
output.WriteString("1")
|
||||
} else {
|
||||
output.WriteString("0")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Packet struct {
|
||||
id int
|
||||
value int
|
||||
subValues int
|
||||
version int
|
||||
subVersions int
|
||||
pType int
|
||||
subpacketCount int
|
||||
bitCount int
|
||||
subBitCount int
|
||||
}
|
||||
|
||||
var packetNum = 0
|
||||
|
||||
func parsePacket(bitReader *BitReader, depth int) (Packet, error) {
|
||||
packetNum++
|
||||
p := Packet{packetNum, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
versionBits, err := bitReader.ReadBits(3)
|
||||
p.bitCount += 3
|
||||
if err != nil {
|
||||
return p, fmt.Errorf("%s for version bits", err.Error())
|
||||
}
|
||||
p.version = bits.ToInt(versionBits)
|
||||
typeBits, err := bitReader.ReadBits(3)
|
||||
p.bitCount += 3
|
||||
if err != nil {
|
||||
return p, fmt.Errorf("%s for type bits", err.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)
|
||||
|
||||
switch p.pType {
|
||||
case 4:
|
||||
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'
|
||||
for bitVals, err = bitReader.ReadBits(5); bitVals[0]; bitVals, err = bitReader.ReadBits(5) {
|
||||
p.bitCount += 5
|
||||
if err != nil {
|
||||
return p, fmt.Errorf("%s for literal bits", err.Error())
|
||||
}
|
||||
litBits = append(litBits, bitVals[1:]...)
|
||||
}
|
||||
// add the last set to the literal value
|
||||
p.bitCount += 5
|
||||
litBits = append(litBits, bitVals[1:]...)
|
||||
p.value = bits.ToInt(litBits)
|
||||
log.Printf(log.DIAGNOSTIC, " (value %d)", p.value)
|
||||
|
||||
return p, nil
|
||||
default:
|
||||
log.Printf(log.DIAGNOSTIC, ": O")
|
||||
hasSubpackets, err := bitReader.ReadBit()
|
||||
p.bitCount += 1
|
||||
if err != nil {
|
||||
return p, fmt.Errorf("%s for subpacket bit", err.Error())
|
||||
}
|
||||
if hasSubpackets {
|
||||
countBits, err := bitReader.ReadBits(11)
|
||||
p.bitCount += 11
|
||||
if err != nil {
|
||||
return p, fmt.Errorf("%s for subpacket count", err.Error())
|
||||
}
|
||||
p.subpacketCount = bits.ToInt(countBits)
|
||||
log.Printf(log.DIAGNOSTIC, " (count: %d) {", p.subpacketCount)
|
||||
|
||||
for subpacketTotal := 0; subpacketTotal < p.subpacketCount; {
|
||||
sp, err := parsePacket(bitReader, depth+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)
|
||||
}
|
||||
subpacketTotal++
|
||||
p.subValues += sp.value + sp.subValues
|
||||
p.subVersions += sp.version + sp.subVersions
|
||||
p.subBitCount += sp.bitCount + sp.subBitCount
|
||||
}
|
||||
} else {
|
||||
lengthBits, err := bitReader.ReadBits(15)
|
||||
p.bitCount += 15
|
||||
if err != nil {
|
||||
return p, fmt.Errorf("%s for subpacket length", err.Error())
|
||||
}
|
||||
p.subBitCount = bits.ToInt(lengthBits)
|
||||
log.Printf(log.DIAGNOSTIC, " (length: %d) {", p.subBitCount)
|
||||
subpacketBits := 0
|
||||
for subpacketBits < p.subBitCount {
|
||||
sp, err := parsePacket(bitReader, depth+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)
|
||||
}
|
||||
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 {
|
||||
return p, fmt.Errorf("packet #%d should parse %d bits but parsed %d", p.id, p.subBitCount, subpacketBits)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if p.pType != 4 {
|
||||
log.Printf(log.DIAGNOSTIC, "\n%s}", strings.Repeat(" ", 6+depth*2))
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
type BitReader struct {
|
||||
file *os.File
|
||||
values []bool
|
||||
}
|
||||
|
||||
func NewBitReader(file *os.File) BitReader {
|
||||
return BitReader{file, []bool{}}
|
||||
}
|
||||
|
||||
var totalBytesRead = 0
|
||||
|
||||
func (b *BitReader) ReadBits(num int) ([]bool, error) {
|
||||
if len(b.values) < num {
|
||||
// each char is worth 4 bits
|
||||
byteCount := int(math.Ceil(float64(num-len(b.values)) / 4))
|
||||
bytes := make([]byte, byteCount)
|
||||
b.file.Read(bytes)
|
||||
log.Printf(log.NEVER, "\n [Reading in %d more byte(s) to fulfill %d bit read]", byteCount, num)
|
||||
totalBytesRead += byteCount
|
||||
err := b.AddToValues(bytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s while reading %d bits", err.Error(), num)
|
||||
}
|
||||
}
|
||||
|
||||
// read the rest from input and set any remainder
|
||||
bits := b.values[:num]
|
||||
b.values = b.values[num:]
|
||||
log.Printf(log.NEVER, " \n [Read %d bits from reader and left %d remainder values]", len(bits), len(b.values))
|
||||
|
||||
return bits, nil
|
||||
}
|
||||
|
||||
func (b *BitReader) ReadBit() (bool, error) {
|
||||
bits, err := b.ReadBits(1)
|
||||
if err == nil {
|
||||
return bits[0], nil
|
||||
} else {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BitReader) AddToValues(bytes []byte) error {
|
||||
for bIdx, byte := range bytes {
|
||||
newBits, err := bits.HexByteToBits(byte)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s @ byte #%d", err.Error(), totalBytesRead-len(bytes)+bIdx+1)
|
||||
}
|
||||
b.values = append(b.values, newBits...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay16(t *testing.T) {
|
||||
assert.IsTrue(t, true, "cool")
|
||||
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
1100001100011100010100101000000100110010011000010001101011001100110000000101001111001100100011001110010110100001010101010011010100111010010010011100100101000001001100001001110001101000100101011000111101011001010100010010100101001110101001011100110010110000001000010001100010000101011000010001100010001000000100000000000101001010000110101100001010110010000100010101001100101110110000111001100011000000000000010101010001000001000101000010110011001000101110000001000101011100001000111100111111000011010111001011111011101111001101011100100101001010010011101001101100010000000000010001011010100100010111111110010100101100011001100101101011001100000100110101100111000110100010011011001011111001100101100101100111110101001001010001000100000011001101011001000100010100011001011000000100011000000101001110000010011100111000001000110011100010011000100001000101011110010100111111001010101110111101011110111001101110110000000000011000010001101111001100001110011100111111111010000011001000001110010010000100010110101010010011110010100101111000010001101101001010100011110100100101011110001001101010011001010101111011111011011010110001000101011000111100111100000110111100010110101110001000000101001011001010000001001110010100000001111101100110000100011001010001000000110000010001101001010110011010111111110010111110011001000000001000000101111111101100111100000011001011000001000100011100011000110110100111101010011001100101010001011000100110010101000010011010110011101010111100011110101101101100000010100011000100011011011011110100000100100101100111001110000000101100101101011011001101010101000010010011111110100010110000011010100101011111011011100000100110000000101000100001000110011001000010000001001010111000000100010001001100101011000101010011001100110100000011000001000100010100001111100001110011000101000010000000110000000000001101000100000000010001010011100100011000000011100101010010010101101000000100101111001110011110110011001010101010000101000011001011101101010101000110001000000100111000010110011111001111101001110000111010100100000001100010010011010011111001111100000010010100010001101010100100111100001001111101010011000111000101000000001010011001101001111011000101000001010110101011000101110010001110100001011100100101011110001000110000010110011001110001001100010001001100000100100001100111000001101011110001000101000011010111100000110011000110010110001000010100001111001011100110000000001100010000010011000100011000010111100110000111000000010000010010000110011110000000101001011000010011000000010001011000010100000100101000100011001001001000011010000010101000000100010011001010110010010101100000111111000110001100010001000101000000001100101011010000100000100011100101001111000101010110100011000100011001011011100100010100101000110000001110010100010001001001101011001010011110000110111010100000010011000000110101111010000101100001010110001111000010100000010011101100111000101011000100000100101010100110001000000100000010000111100110001000010100001001000001000100010100000011100011101011000101111010001010010010000001000101000000010011001011001101001010000010000100101001000001001010010100000100101100100100111100001001010100101101000000010110010101101110000000000100010001001110111100010010010101111011001001110011000011010111001110011010000110101001101010010000001001001101011011100010101001110011111111111000001010100101100010011011100101010110010000010001000101000100010100101001001011101110110101010010011000010000100101000100011011001101101100010111100110111000000001011010001001100111000101101101001100010100011001001101001011010101011110111100110101010010110100100001101000100000010100001011001100000100010100101001010011011011101100000011111010111011001011110010110011001110010101101011101011110010011000010011100001100011100001000101100101110000100001001010000010001111100001000101100000100000010010001101100001000101011010100000010010001101000001010010001100101100010010000111000100110000010000110011001001000100011110001001101010000100010101001100010001101110011000111000010001010110000001000110010010111011100001000101001011000100010110100100010011000100010100101100010001010000100001000100010001101011110001000100010010010110010000000000110011000000100001000101101000100000010010000110011000010100100010011010100000001000101000000100001100000101011110000011001100010010110000000100010110011000011011110001010011100000001100000100010001100000101100111100110110010010010010000101001001111100001100011010010001111010011000000100110101000010010110011000101110000100011100010000010001000100100001101010001011100100101111001100100010100010000001000000000010000110100011111101000000000010010110011010011001110001010000000000010001010111100000010111101000000100110000000000100010101001001011101110011001011000100101001101001010010011100011110000010011010111101100100011000110111101011001010100111100001101010011100010110000000000001111101001001010110000001000011011000001101001010110111100001001110001011100101101010101001100010001110010010011100000010010000100101001111001011001100111100101101Line truncated
|
||||
@@ -1,5 +1,7 @@
|
||||
package bits
|
||||
|
||||
import "fmt"
|
||||
|
||||
func GetBitCount(val int) int {
|
||||
count := 0
|
||||
for val != 0 {
|
||||
@@ -52,3 +54,66 @@ func BitwiseAndA(a ...int) int {
|
||||
func ByBitCount(size int) func(int) bool {
|
||||
return func(val int) bool { return GetBitCount(val) == size }
|
||||
}
|
||||
|
||||
func ToInt(bits []bool) int {
|
||||
intVal := 0
|
||||
for idx := 0; idx < len(bits); idx++ {
|
||||
intVal = intVal << 1
|
||||
if bits[idx] {
|
||||
intVal += 1
|
||||
}
|
||||
}
|
||||
return intVal
|
||||
}
|
||||
|
||||
func ToStr(bits []bool) string {
|
||||
str := ""
|
||||
for idx := 0; idx < len(bits); idx++ {
|
||||
if bits[idx] {
|
||||
str += "1"
|
||||
} else {
|
||||
str += "0"
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func HexByteToBits(b byte) ([]bool, error) {
|
||||
// just do this manually because i can't be arsed
|
||||
switch b {
|
||||
case byte('0'):
|
||||
return []bool{false, false, false, false}, nil
|
||||
case byte('1'):
|
||||
return []bool{false, false, false, true}, nil
|
||||
case byte('2'):
|
||||
return []bool{false, false, true, false}, nil
|
||||
case byte('3'):
|
||||
return []bool{false, false, true, true}, nil
|
||||
case byte('4'):
|
||||
return []bool{false, true, false, false}, nil
|
||||
case byte('5'):
|
||||
return []bool{false, true, false, true}, nil
|
||||
case byte('6'):
|
||||
return []bool{false, true, true, false}, nil
|
||||
case byte('7'):
|
||||
return []bool{false, true, true, true}, nil
|
||||
case byte('8'):
|
||||
return []bool{true, false, false, false}, nil
|
||||
case byte('9'):
|
||||
return []bool{true, false, false, true}, nil
|
||||
case byte('A'):
|
||||
return []bool{true, false, true, false}, nil
|
||||
case byte('B'):
|
||||
return []bool{true, false, true, true}, nil
|
||||
case byte('C'):
|
||||
return []bool{true, true, false, false}, nil
|
||||
case byte('D'):
|
||||
return []bool{true, true, false, true}, nil
|
||||
case byte('E'):
|
||||
return []bool{true, true, true, false}, nil
|
||||
case byte('F'):
|
||||
return []bool{true, true, true, true}, nil
|
||||
default:
|
||||
return []bool{}, fmt.Errorf("read invalid byte")
|
||||
}
|
||||
}
|
||||
@@ -26,3 +26,37 @@ func TestByBitCount(t *testing.T) {
|
||||
twoBitFilter := ByBitCount(2)
|
||||
assert.IsTrue(t, twoBitFilter(17 /*10001*/), "should count bits")
|
||||
}
|
||||
|
||||
func TestHexByteToBits(t *testing.T) {
|
||||
cases := []struct {
|
||||
input rune
|
||||
output string
|
||||
}{
|
||||
{'0', "0000"},
|
||||
{'1', "0001"},
|
||||
{'2', "0010"},
|
||||
{'3', "0011"},
|
||||
{'4', "0100"},
|
||||
{'5', "0101"},
|
||||
{'6', "0110"},
|
||||
{'7', "0111"},
|
||||
{'8', "1000"},
|
||||
{'9', "1001"},
|
||||
{'A', "1010"},
|
||||
{'B', "1011"},
|
||||
{'C', "1100"},
|
||||
{'D', "1101"},
|
||||
{'E', "1110"},
|
||||
{'F', "1111"},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
bits, err := HexByteToBits(byte(c.input))
|
||||
if err != nil {
|
||||
t.Logf("Got error from HexByteToBits: %s", err.Error())
|
||||
t.Fail()
|
||||
}
|
||||
bitStr := ToStr(bits)
|
||||
assert.EqualsStr(t, bitStr, c.output, "incorrect value")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func CreateOrReplace(fileName string) (*os.File, error) {
|
||||
var output *os.File
|
||||
if _, err := os.Stat(fileName); errors.Is(err, os.ErrNotExist) {
|
||||
output, err = os.Create(fileName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error creating file %s", fileName)
|
||||
}
|
||||
} else {
|
||||
err = os.Truncate(fileName, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error truncating file %s", fileName)
|
||||
}
|
||||
output, err = os.Open(fileName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error opening file %s", fileName)
|
||||
}
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
+30
-1
@@ -1,12 +1,16 @@
|
||||
package log
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
NONE = 0
|
||||
NORMAL = 1
|
||||
DEBUG = 2
|
||||
DIAGNOSTIC = 3
|
||||
NEVER = 99
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -24,6 +28,31 @@ func SetLogLevel(level int) {
|
||||
}
|
||||
}
|
||||
|
||||
func SetLogLevelFromArgs(argMap map[string]string) {
|
||||
logLevelStr, found := argMap["log"]
|
||||
if found {
|
||||
logLevel, err := NORMAL, error(nil)
|
||||
|
||||
switch logLevelStr {
|
||||
case "NONE", "None", "none":
|
||||
logLevel = NONE
|
||||
case "NORMAL", "Normal", "normal":
|
||||
logLevel = NORMAL
|
||||
case "DEBUG", "Debug", "debug":
|
||||
logLevel = DEBUG
|
||||
case "DIAG", "DIAGNOSTIC", "Diag", "Diagnostic", "diag", "diagnostic":
|
||||
logLevel = DIAGNOSTIC
|
||||
default:
|
||||
logLevel, err = strconv.Atoi(logLevelStr)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
panic("Error when parsing log level")
|
||||
}
|
||||
SetLogLevel(logLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func Print(minLevel int, a ...interface{}) (int, error) {
|
||||
if LOG_LEVEL >= minLevel {
|
||||
return fmt.Print(a...)
|
||||
|
||||
@@ -9,3 +9,21 @@ func Min(i1 int, a ...int) int {
|
||||
}
|
||||
return min
|
||||
}
|
||||
|
||||
func Max(i1 int, a ...int) int {
|
||||
max := i1
|
||||
for _, i := range a {
|
||||
if i > max {
|
||||
max = i
|
||||
}
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
func BoolToInt(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user