diff --git a/2018/day12-2.go b/2018/day12-2.go new file mode 100644 index 0000000..4efd8b3 --- /dev/null +++ b/2018/day12-2.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + + "internal/day12" + "internal/util" +) + +const NumGenerations = 50000000000 + +func main() { + data := util.ReadInput() + plants, rules := day12.FastParseInput(data) + rootIndex := 0 + + for i := 0; i < NumGenerations; i++ { + plants, rootIndex = day12.FastRunGeneration(plants, rules, rootIndex) + + // debug + if i%1000000 == 0 { + fmt.Println("DEBUG: Generation: ", i) + } + } + + fmt.Println(day12.FastSumPlants(plants, rootIndex)) +} diff --git a/2018/internal/day12/fastplants.go b/2018/internal/day12/fastplants.go new file mode 100644 index 0000000..fb9ebbc --- /dev/null +++ b/2018/internal/day12/fastplants.go @@ -0,0 +1,56 @@ +package day12 + +func FastRunGeneration(plants []byte, rules map[string]byte, rootIndex int) ([]byte, int) { + newGen := make([]byte, len(plants), len(plants)+4) + + for i := 0; i < len(plants); i++ { + newGen[i] = rules[getKey(plants, i)] + } + + result1 := rules[getKey(plants, -2)] + result2 := rules[getKey(plants, -1)] + if result1 == '#' || result2 == '#' { + newGen = append([]byte{result1, result2}, newGen...) + rootIndex += 2 + } + + result1 = rules[getKey(plants, len(plants))] + result2 = rules[getKey(plants, len(plants)+1)] + if result1 == '#' || result2 == '#' { + newGen = append(newGen, result1, result2) + } + + return newGen, rootIndex +} + +func getKey(plants []byte, i int) string { + if i < 2 { + key := "" + for j := 0; j < 2-i; j++ { + key += "." + } + key += string(plants[0 : i+2]) + return key + } + + if i > len(plants)-2 { + key := string(plants[i-2 : len(plants)-1]) + for j := 0; j < len(plants)-1-i; j++ { + key += "." + } + key += string(plants[0 : i+2]) + return key + } + + return string(plants[i-2 : i+2]) +} + +func FastSumPlants(plants []byte, rootIndex int) int { + sum := 0 + for index, value := range plants { + if value == '#' { + sum += index - rootIndex + } + } + return sum +} diff --git a/2018/internal/day12/input.go b/2018/internal/day12/input.go index 8c82a2a..3f066ca 100644 --- a/2018/internal/day12/input.go +++ b/2018/internal/day12/input.go @@ -40,3 +40,21 @@ func ParseInput(data []string) (map[int]bool, []*Rule) { return plants, rules } + +// The function isn't fast, the resulting data is. +func FastParseInput(data []string) ([]byte, map[string]byte) { + stateStrings := strings.Split(data[0], " ") + ruleStrings := data[2:] + + // Populate plant list + plants := []byte(stateStrings[len(stateStrings)-1]) + + // Create rules + rules := make(map[string]byte) + for _, ruleStr := range ruleStrings { + ruleData := strings.Split(ruleStr, " ") + rules[ruleData[0]] = []byte(ruleData[2])[0] + } + + return plants, rules +} diff --git a/2018/internal/day12/plants.go b/2018/internal/day12/plants.go index 0a09db4..c4e687d 100644 --- a/2018/internal/day12/plants.go +++ b/2018/internal/day12/plants.go @@ -53,6 +53,7 @@ func RunGeneration(plants map[int]bool, rules []*Rule) map[int]bool { for _, rule := range rules { if checkRule(plants, rule, i) { newGen[i] = rule.Result + break // only one rule will match a given slice } } }