Files
advent-of-code-2021/day-14/main.go
T

165 lines
4.3 KiB
Go
Raw Normal View History

2021-12-15 16:52:42 -05:00
/* Day 14: Extended Polymerization */
package main
import (
"AoC2021/utils/args"
"AoC2021/utils/log"
"AoC2021/utils/timer"
"bufio"
"math"
"os"
"strconv"
"strings"
)
func main() {
argMap := args.Parse(os.Args)
setLogLevel(argMap)
selectedPart, partSpecified := argMap["part"]
log.Println(log.NORMAL, "--- Day 14: Extended Polymerization ---")
timer.Start()
if !partSpecified || selectedPart == "1" {
part1()
timer.TickAtLevel(log.NORMAL)
log.Println(log.NORMAL)
}
if !partSpecified || selectedPart == "2" {
part2()
timer.TickAtLevel(log.NORMAL)
log.Println(log.NORMAL)
}
}
func part1() {
log.Println(log.NORMAL, "* Part 1 *")
log.Println(log.NORMAL, " Goal: Apply 10 steps of pair insertion to the polymer template and find the most and least common elements in the result.")
log.Println(log.NORMAL, " Answer: What do you get if you take the quantity of the most common element and subtract the quantity of the least common element?")
doTheThing(10)
}
func part2() {
log.Println(log.NORMAL, "* Part 2 *")
log.Println(log.NORMAL, " Goal: Apply 40 steps of pair insertion to the polymer template and find the most and least common elements in the result.")
log.Println(log.NORMAL, " Answer: What do you get if you take the quantity of the most common element and subtract the quantity of the least common element?")
doTheThing(40)
}
func doTheThing(totalSteps int) {
template, pairs := readInput()
log.Println(log.DIAGNOSTIC, template, pairs)
// perform the loop 'totalSteps' times
for step := 0; step < totalSteps; step++ {
// starting from the front of the template, check two-letter pairs
for tIdx := 0; tIdx < len(template)-1; tIdx++ {
// the lookup key will be the next two letters in the template
key := template[tIdx : tIdx+2]
// if we find a match in the pairs map
value, found := pairs[key]
if found {
// insert the new character between the original two letters
template = template[:tIdx+1] + value + template[tIdx+1:]
// increment the idx counter once more so that we skip over the character that we just inserted
tIdx++
}
}
log.Printf(log.DEBUG, "After step #%d template is length %d\n", step+1, len(template))
timer.TickAtLevel(log.DEBUG)
}
// COUNT all character occurances
countMap := make(map[byte]int)
for idx := 0; idx < len(template); idx++ {
countMap[template[idx]]++
}
log.Println(log.DIAGNOSTIC, "CountMap:", countMap)
mostCommonLetter, mostCommonCount := getMostCommon(countMap)
leastCommonLetter, leastCommonCount := getLeastCommon(countMap)
log.Printf(log.NORMAL, "After %d steps, the most common (%s=%d) minus the least common (%s=%d) is %d\n", totalSteps, mostCommonLetter, mostCommonCount, leastCommonLetter, leastCommonCount, mostCommonCount-leastCommonCount)
}
func check(e error) {
if e != nil {
log.Println(log.DEBUG, "Oh snap!")
panic(e)
}
}
func setLogLevel(argMap map[string]string) {
logLevelStr, found := argMap["log"]
if found {
logLevel, err := strconv.Atoi(logLevelStr)
check(err)
log.SetLogLevel(logLevel)
}
}
func readInput() (string, map[string]string) {
input, err := os.Open("./input.txt")
check(err)
defer input.Close()
scanner := bufio.NewScanner(input)
lines := 0
// TEMPLATE LINE
if !scanner.Scan() {
panic("Error parsing input template")
}
template := scanner.Text()
lines++
// NEW LINE
if !scanner.Scan() {
panic("Error parsing input newline")
}
_ = scanner.Text()
lines++
// PAIRS
pairs := make(map[string]string)
for scanner.Scan() {
pair := strings.Split(scanner.Text(), " -> ")
if len(pair) != 2 {
panic("Error parsing input pairs")
}
pairs[pair[0]] = pair[1]
lines++
}
log.Printf(log.NORMAL, "Read %d pairs from %d lines in input\n", len(pairs), lines)
return template, pairs
}
func getMostCommon(countMap map[byte]int) (string, int) {
mostCommonStr := ""
mostCommonCount := -math.MaxInt
for key, value := range countMap {
if value > mostCommonCount {
mostCommonStr, mostCommonCount = string(key), value
}
}
return mostCommonStr, mostCommonCount
}
func getLeastCommon(countMap map[byte]int) (string, int) {
leastCommonStr := ""
leastCommonCount := math.MaxInt
for key, value := range countMap {
if value < leastCommonCount {
leastCommonStr, leastCommonCount = string(key), value
}
}
return leastCommonStr, leastCommonCount
}