diff --git a/2020/day19.go b/2020/day19.go index 6fd40bf..306edf1 100644 --- a/2020/day19.go +++ b/2020/day19.go @@ -9,16 +9,16 @@ import ( "git.annabunch.es/annabunches/adventofcode/2020/lib/util" ) -type Node struct { - name string - children [][]*Node -} - const ( STATE_RULES = iota STATE_DATA ) +type Node struct { + name string + children [][]*Node +} + func NewRule(name string) *Node { return &Node{ name: name, @@ -26,8 +26,6 @@ func NewRule(name string) *Node { } } -var expandRe = regexp.MustCompile("[0-9]+") - func parseRule(name string, rules map[string]string) *Node { ruleString := rules[name] rule := NewRule(name) @@ -50,12 +48,11 @@ func parseRule(name string, rules map[string]string) *Node { return rule } -func parseInput(input []string) (map[string]bool, []string) { +func parseInput(input []string) (map[string]string, []string) { stateRe := regexp.MustCompile("^([0-9]+): (.*)$") state := STATE_RULES data := make([]string, 0) - var root *Node rules := make(map[string]string) // unparsed rules for _, line := range input { @@ -75,8 +72,11 @@ func parseInput(input []string) (map[string]bool, []string) { } } - // now parse the rules we stored - root = parseRule("0", rules) + return rules, data +} + +func createLanguage(rules map[string]string, rootName string) map[string]bool { + root := parseRule(rootName, rules) // now we expand the grammar - generate all possible strings in the language rawLanguage := expand(root) @@ -85,7 +85,7 @@ func parseInput(input []string) (map[string]bool, []string) { language[term] = true } - return language, data + return language } // Expand the list of all possible substrings starting with node @@ -133,13 +133,61 @@ func combine(terms [][]string, acc string) []string { } func main() { - // step := os.Args[1] + step := os.Args[1] values := util.InputParserStrings(os.Args[2]) - language, data := parseInput(values) + rules, data := parseInput(values) count := 0 - for _, item := range data { - if language[item] { - count++ + + switch step { + case "1": + language := createLanguage(rules, "0") + for _, item := range data { + if language[item] { + count++ + } + } + case "2": + // stub + // for step 2, our base rule expands to 0: 42{N} 31{M}, for N > M and N > 2 + // we exploit this, along with the fact that all valid strings for 42 and 31 are + // 8 characters long, to "cheat" a little + matchLength := 8 + left := createLanguage(rules, "42") + right := createLanguage(rules, "31") + + for _, item := range data { + leftCount := 0 + rightCount := 0 + onLeft := true + valid := true // valid until proven otherwise + + for index := 0; index < len(item); index += matchLength { + if len(item[index:]) < matchLength { + fmt.Println("Bad Length") + valid = false // wrong length alignment + break + } + subString := item[index : index+matchLength] + if onLeft { + if left[subString] { + leftCount++ + } else { + onLeft = false + } + } + if !onLeft { + if right[subString] { + rightCount++ + } else { + valid = false + break + } + } + } + + if valid && leftCount > 1 && rightCount > 0 && leftCount > rightCount { + count++ + } } } fmt.Println(count)