2021 Day 14 Part 1
This commit is contained in:
parent
9077b5189b
commit
4804e6b4ab
1 changed files with 128 additions and 0 deletions
128
2021/day14/main.go
Normal file
128
2021/day14/main.go
Normal 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]++
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue