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

2021 Day 14 Part 1

This commit is contained in:
Jeremy Kaplan 2021-12-13 21:59:30 -08:00
commit 4804e6b4ab

128
2021/day14/main.go Normal file
View file

@ -0,0 +1,128 @@
package main
import (
"errors"
"fmt"
"io"
"sort"
"strings"
"github.com/jdkaplan/advent-of-code/aoc"
)
func main() {
text := aoc.Input().ReadFile("day14.txt")
start, rules := parse(text)
fmt.Println(run(start, rules, 10))
}
type Rule struct {
a, b, i rune
}
func parse(text string) (string, []Rule) {
start, lines := aoc.Cut(text, "\n\n")
var rules []Rule
for _, l := range strings.Split(lines, "\n") {
pair, ins := aoc.Cut(l, " -> ")
a, b := (pair[0]), pair[1]
rules = append(rules, Rule{rune(a), rune(b), rune(ins[0])})
}
return start, rules
}
type Re map[rune]map[rune]rune
func (r Re) Get(a, b rune) (rune, bool) {
inner, ok := r[a]
if !ok {
return rune(0), false
}
ins, ok := inner[b]
return ins, ok
}
func (r Re) Put(a, b, i rune) {
inner, ok := r[a]
if !ok {
inner = make(map[rune]rune)
r[a] = inner
}
inner[b] = i
}
func run(s string, rules []Rule, steps int) int {
re := make(Re)
for _, r := range rules {
re.Put(r.a, r.b, r.i)
}
for i := 0; i < steps; i++ {
s = expand(s, re)
}
counts := countChars(s)
var chars []rune
for r := range counts {
chars = append(chars, r)
}
sort.Slice(chars, func(i, j int) bool {
return counts[chars[i]] < counts[chars[j]]
})
min, max := chars[0], chars[len(chars)-1]
return counts[max] - counts[min]
}
func expand(s string, re Re) string {
w := pairs(s)
var sb strings.Builder
for {
a, b, err := w.Next()
if errors.Is(err, io.EOF) {
sb.WriteRune(a)
break
} else if err != nil {
panic(err)
}
sb.WriteRune(a)
if i, ok := re.Get(a, b); ok {
sb.WriteRune(i)
}
}
return sb.String()
}
type Window struct {
prev rune
r *strings.Reader
}
func (w *Window) Next() (a rune, b rune, err error) {
a = w.prev
b, _, err = w.r.ReadRune()
w.prev = b
return
}
func pairs(s string) *Window {
w := &Window{r: strings.NewReader(s)}
_, _, err := w.Next()
if err != nil {
panic(err)
}
return w
}
func countChars(s string) map[rune]int {
r := strings.NewReader(s)
m := make(map[rune]int)
for {
c, _, err := r.ReadRune()
if errors.Is(err, io.EOF) {
return m
} else if err != nil {
panic(err)
}
m[c]++
}
}