Watch
1
0
Fork
You've already forked advent-of-code
0

2021 Day 16 Part 1

This commit is contained in:
Jeremy Kaplan 2021-12-15 22:25:10 -08:00
commit 28db460d7b
2 changed files with 162 additions and 0 deletions

View file

@ -39,6 +39,14 @@ func MustInt(s string) int {
return i
}
func MustHex(s string) int {
i, err := strconv.ParseInt(s, 16, 0)
if err != nil {
panic(err)
}
return int(i)
}
type Inputs struct {
fs fs.FS
}

154
2021/day16/main.go Normal file
View file

@ -0,0 +1,154 @@
package main
import (
"fmt"
"strings"
"github.com/jdkaplan/advent-of-code/aoc"
)
func main() {
text := aoc.Input().ReadFile("day16.txt")
fmt.Println(part1(parse(text)))
}
type bits []int
func (b bits) String() string {
var sb strings.Builder
for _, x := range b {
fmt.Fprintf(&sb, "%b", x)
}
return sb.String()
}
func (b bits) Uint() uint {
var u uint
for _, i := range b {
u <<= 1
u += uint(i)
}
return u
}
func (b bits) Consume(n uint) (prefix uint, extra bits) {
return b[:n].Uint(), b[n:]
}
func parse(text string) (b bits) {
for _, char := range strings.Split(text, "") {
x := aoc.MustHex(char)
for i := 3; i >= 0; i-- {
b = append(b, (x>>i)&1)
}
}
return
}
func part1(b bits) uint {
p, _ := packet(b)
return sumVersions(p)
}
func sumVersions(p Packet) uint {
switch p := p.(type) {
case Literal: // no-op
return p.Version()
case Operator:
sum := p.Version()
for _, inner := range p.Packets {
sum += sumVersions(inner)
}
return sum
default:
panic(fmt.Sprintf("Unknown data type: %T", p))
}
}
type Packet interface {
Version() uint
Type() uint
}
type Literal struct {
V, T uint
Value uint
}
func (l Literal) Version() uint { return l.V }
func (l Literal) Type() uint { return l.T }
type Operator struct {
V, T uint
Packets []Packet
}
func (o Operator) Version() uint { return o.V }
func (o Operator) Type() uint { return o.T }
func packet(b bits) (Packet, bits) {
v, b := b.Consume(3)
t, b := b.Consume(3)
switch t {
case 4:
var val uint
val, b = literal(b)
return Literal{v, t, val}, b
default:
var ps []Packet
ps, b = operator(b)
return Operator{v, t, ps}, b
}
}
func literal(b bits) (uint, bits) {
var val uint
for {
var n uint
n, b = b.Consume(5)
val <<= 4
val += n & 0b01111
if n&0b10000 == 0 {
break
}
}
return val, b
}
func operator(b bits) ([]Packet, bits) {
lt, b := b.Consume(1)
var ps []Packet
if lt == 0 {
var l uint
l, b = b.Consume(15)
taken := uint(0)
for l-taken > 6 { // min length for a packet
var p Packet
oldlen := len(b)
p, b = packet(b)
ps = append(ps, p)
taken += uint(oldlen - len(b))
}
b = padding(b, l-taken)
return ps, b
} else {
var n uint
n, b = b.Consume(11)
for i := uint(0); i < n; i++ {
var p Packet
p, b = packet(b)
ps = append(ps, p)
}
return ps, b
}
}
func padding(b bits, n uint) bits {
u, b := b.Consume(n)
if u != 0 {
panic(fmt.Sprintf("Expected padding, got nonzero bits: %b", u))
}
return b
}