adventofcode/2015/day19/main.go
2016-12-16 16:21:15 -06:00

124 lines
2.7 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
var input []string
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input = append(input, scanner.Text())
}
transforms := make(map[string][]string)
var stMolecule string
for i := range input {
if strings.Contains(input[i], "=>") {
parts := strings.Split(input[i], " => ")
transforms[parts[0]] = append(transforms[parts[0]], parts[1])
} else if len(input[i]) > 0 {
// Must be the calibration molecule
stMolecule = input[i]
}
}
fmt.Println("*** CALIBRATION ***")
res := calibrate(stMolecule, transforms)
fmt.Println("Found " + strconv.Itoa(len(res)) + " combinations")
fmt.Println("\n")
fmt.Println("*** MANUFACTURING ***")
backTrans := reverseTransforms(transforms)
manufacture(stMolecule, backTrans, 0)
}
// stepBack takes an ending string and a reversed list of the transformations
func manufacture(molecule string, transforms map[string][]string, steps int) {
fmt.Println(molecule)
if molecule == "e" {
fmt.Println("Found in " + strconv.Itoa(steps) + " steps")
os.Exit(0)
}
for k, v := range transforms {
if strings.Contains(molecule, k) {
for i := range v {
tstVal := strings.Replace(molecule, k, v[i], 1)
manufacture(tstVal, transforms, steps+1)
}
}
}
}
func reverseTransforms(t map[string][]string) map[string][]string {
ret := make(map[string][]string)
for v := range t {
for j := range t[v] {
ret[t[v][j]] = append(ret[t[v][j]], v)
}
}
return ret
}
func calibrate(molecule string, transforms map[string][]string) []string {
var ret []string
atoms := getAtomsFromMolecule(molecule)
for i := range atoms {
// Build a string of atoms before i
start := strings.Join(atoms[:i], "")
// And all after i too
end := strings.Join(atoms[i+1:], "")
// Find all transforms for atoms[i]
if v, ok := transforms[atoms[i]]; ok {
for j := range v {
ret = uniqueInsert(ret, start+v[j]+end)
//ret = append(ret, start+v[j]+end)
}
}
}
return ret
}
func getAtomsFromMolecule(molecule string) []string {
var atoms []string
var bldAtom string
for i := range molecule {
if molecule[i] >= 'A' && molecule[i] <= 'Z' {
if len(bldAtom) > 0 {
atoms = append(atoms, bldAtom)
}
bldAtom = string(molecule[i])
continue
}
bldAtom = bldAtom + string(molecule[i])
}
return append(atoms, bldAtom)
}
func uniqueInsert(curr []string, ins string) []string {
for i := range curr {
if curr[i] == ins {
return curr
}
}
return append(curr, ins)
}
func mustAtoi(s string) int {
var i int
var err error
if i, err = strconv.Atoi(s); err != nil {
fmt.Println("Tried to atoi " + s)
os.Exit(1)
}
return i
}