Day 14 solution
This commit is contained in:
146
fourteen/polymer.go
Normal file
146
fourteen/polymer.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package fourteen
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type polymer struct {
|
||||
template string
|
||||
rules map[string]string
|
||||
}
|
||||
|
||||
func (p *polymer) load(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
p.rules = map[string]string{}
|
||||
scannedTemplate := false
|
||||
for scanner.Scan() {
|
||||
if !scannedTemplate {
|
||||
p.template = scanner.Text()
|
||||
|
||||
scannedTemplate = true
|
||||
continue
|
||||
}
|
||||
|
||||
if scanner.Text() == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
var pair, insert string
|
||||
if count, err := fmt.Sscanf(scanner.Text(), "%s -> %s", &pair, &insert); count != 2 || err != nil {
|
||||
return fmt.Errorf("expected to scan 2 values from %q, found %d: %w", scanner.Text(), count, err)
|
||||
}
|
||||
p.rules[pair] = insert
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *polymer) elementCount(size int) int {
|
||||
result := p.step(size)
|
||||
elemCounts := map[rune]int{}
|
||||
|
||||
for _, r := range result {
|
||||
elemCounts[r]++
|
||||
}
|
||||
|
||||
min := len(result)
|
||||
max := 0
|
||||
for _, v := range elemCounts {
|
||||
if v < min {
|
||||
min = v
|
||||
}
|
||||
|
||||
if v > max {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
|
||||
return max - min
|
||||
}
|
||||
|
||||
func (p *polymer) elementCountMap(size int) int {
|
||||
_, counts := p.stepMap(size)
|
||||
|
||||
min := -1
|
||||
max := -1
|
||||
for _, v := range counts {
|
||||
if v < min || min == -1 {
|
||||
min = v
|
||||
}
|
||||
|
||||
if v > max {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
|
||||
return max - min
|
||||
}
|
||||
|
||||
func (p *polymer) stepMap(steps int) (map[string]int, map[string]int) {
|
||||
pairs := map[string]int{}
|
||||
counts := map[string]int{}
|
||||
|
||||
// Build initial pairs and counts from template
|
||||
for i := 0; i < len(p.template)-1; i++ {
|
||||
// Count first element from pair
|
||||
counts[string(p.template[i])]++
|
||||
pairs[fmt.Sprintf("%c%c", p.template[i], p.template[i+1])]++
|
||||
// If this is the last pair add the second element
|
||||
if i == len(p.template)-2 {
|
||||
counts[string(p.template[i+1])]++
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < steps; i++ {
|
||||
pairs, counts = p.stepMapOne(pairs, counts)
|
||||
}
|
||||
|
||||
return pairs, counts
|
||||
}
|
||||
|
||||
func (p *polymer) stepMapOne(pairs map[string]int, counts map[string]int) (map[string]int, map[string]int) {
|
||||
newPairs := map[string]int{}
|
||||
for k, v := range pairs {
|
||||
result := p.rules[k]
|
||||
counts[result] += (1 * v)
|
||||
pair1 := fmt.Sprintf("%c%s", k[0], result)
|
||||
pair2 := fmt.Sprintf("%s%c", result, k[1])
|
||||
newPairs[pair1] += 1 * v
|
||||
newPairs[pair2] += 1 * v
|
||||
}
|
||||
|
||||
return newPairs, counts
|
||||
}
|
||||
|
||||
func (p *polymer) step(steps int) string {
|
||||
seed := p.template
|
||||
for i := 0; i < steps; i++ {
|
||||
seed = p.stepOne(seed)
|
||||
}
|
||||
|
||||
return seed
|
||||
}
|
||||
|
||||
func (p *polymer) stepOne(from string) string {
|
||||
result := ""
|
||||
for i := 0; i < len(from)-1; i++ {
|
||||
// Add first element from pair
|
||||
result += string(from[i])
|
||||
// Lookup and add element result from pair
|
||||
pair := fmt.Sprintf("%c%c", from[i], from[i+1])
|
||||
result += p.rules[pair]
|
||||
// If this is the last pair add the second element
|
||||
if i == len(from)-2 {
|
||||
result += string(from[i+1])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
Reference in New Issue
Block a user