116 lines
2.3 KiB
Go
116 lines
2.3 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
func GetRule(rules *map[string]string, r string) string {
|
|
rule := (*rules)[r]
|
|
|
|
if strings.Contains(rule, `"`) {
|
|
// Base case
|
|
matchLetter := rule[1 : len(rule)-1]
|
|
return matchLetter
|
|
}
|
|
|
|
alternates := strings.Split(rule, " | ")
|
|
|
|
if len(alternates) == 1 {
|
|
ruleNumbers := strings.Split(alternates[0], " ")
|
|
str := ""
|
|
for _, n := range ruleNumbers {
|
|
str += GetRule(rules, n)
|
|
}
|
|
return str
|
|
}
|
|
|
|
if len(alternates) > 1 {
|
|
ruleNumbers := strings.Split(alternates[0], " ")
|
|
firstAlternate := ""
|
|
for _, n := range ruleNumbers {
|
|
firstAlternate += GetRule(rules, n)
|
|
}
|
|
|
|
ruleNumbers = strings.Split(alternates[1], " ")
|
|
secondAlternate := ""
|
|
for _, n := range ruleNumbers {
|
|
secondAlternate += GetRule(rules, n)
|
|
}
|
|
|
|
return fmt.Sprintf("(%s|%s)", firstAlternate, secondAlternate)
|
|
}
|
|
|
|
panic("should never be here")
|
|
}
|
|
|
|
func main() {
|
|
|
|
content, err := os.ReadFile("./input.txt")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
splitInput := strings.Split(string(content), "\n\n")
|
|
rules := strings.Split(splitInput[0], "\n")
|
|
|
|
ruleMap := make(map[string]string)
|
|
|
|
for _, rule := range rules {
|
|
splitRule := strings.Split(rule, ": ")
|
|
ruleNumber := splitRule[0]
|
|
|
|
ruleMap[ruleNumber] = splitRule[1]
|
|
}
|
|
|
|
tests := splitInput[1]
|
|
tests = tests[0 : len(tests)-1]
|
|
|
|
zeroRule := regexp.MustCompile("^" + GetRule(&ruleMap, "0") + "$")
|
|
|
|
matches := 0
|
|
for _, t := range strings.Split(tests, "\n") {
|
|
if zeroRule.Match([]byte(t)) {
|
|
matches++
|
|
}
|
|
}
|
|
|
|
fmt.Printf("Part 1: %d\n", matches)
|
|
|
|
fRule := regexp.MustCompile(GetRule(&ruleMap, "42"))
|
|
tRule := regexp.MustCompile(GetRule(&ruleMap, "31"))
|
|
|
|
matches = 0
|
|
for _, t := range strings.Split(tests, "\n") {
|
|
|
|
// rule 0 = 8 11
|
|
// 8 = 42+
|
|
// 11 = 42{n} 31{n}
|
|
// Therefore: 0 = 42 {n*2} 31{n}
|
|
|
|
fortyTwoMatch := fRule.FindStringIndex(t)
|
|
fortyTwoCount := 0
|
|
for fortyTwoMatch != nil && fortyTwoMatch[0] == 0 {
|
|
t = t[fortyTwoMatch[1]:]
|
|
fortyTwoMatch = fRule.FindStringIndex(t)
|
|
fortyTwoCount++
|
|
}
|
|
|
|
thirtyMatch := tRule.FindStringIndex(t)
|
|
thirtyCount := 0
|
|
for thirtyMatch != nil && thirtyMatch[0] == 0 {
|
|
t = t[thirtyMatch[1]:]
|
|
thirtyMatch = tRule.FindStringIndex(t)
|
|
thirtyCount++
|
|
}
|
|
|
|
if len(t) == 0 && thirtyCount > 0 && fortyTwoCount > thirtyCount {
|
|
matches++
|
|
}
|
|
}
|
|
|
|
fmt.Printf("Part 2: %d\n", matches)
|
|
}
|