-
Notifications
You must be signed in to change notification settings - Fork 0
/
day19.go
108 lines (98 loc) · 2.43 KB
/
day19.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package main
import (
"fmt"
"io/ioutil"
"os"
"regexp"
"strconv"
"strings"
)
var loopDetect map[int]int
var cache map[int]string
func main() {
i, err := ioutil.ReadFile("input.txt")
if err != nil {
os.Exit(1)
}
input := string(i)
fmt.Printf("Part 1: %v\n", SolveDay19Part1(input))
fmt.Printf("Part 2: %v\n", SolveDay19Part2(input))
}
func init() {
loopDetect = make(map[int]int)
}
//SolveDay19Part1 return the number of strings that matched the rules
func SolveDay19Part1(input string) (s int) {
blocks := strings.Split(input, "\n\n")
if len(blocks) != 2 {
return 0
}
rules := make(map[int]string)
for _, line := range strings.Split(blocks[0], "\n") {
splitLine := strings.Split(line, ": ")
ruleId, _ := strconv.Atoi(splitLine[0])
rules[ruleId] = splitLine[1]
}
cache = make(map[int]string)
regex := "^" + resolveRulesRegex(0, rules) + "$"
r, _ := regexp.Compile(regex)
for _, line := range strings.Split(blocks[1], "\n") {
if r.MatchString(line) {
s++
}
}
return
}
//SolveDay19Part2 return the number of strings that matched the rules (with updated rule 8 und 11)
func SolveDay19Part2(input string) (s int) {
blocks := strings.Split(input, "\n\n")
if len(blocks) != 2 {
return 0
}
rules := make(map[int]string)
for _, line := range strings.Split(blocks[0], "\n") {
splitLine := strings.Split(line, ": ")
ruleId, _ := strconv.Atoi(splitLine[0])
rules[ruleId] = splitLine[1]
}
rules[8] = "42 | 42 8"
rules[11] = "42 31 | 42 11 31"
cache = make(map[int]string)
regex := "^" + resolveRulesRegex(0, rules) + "$"
r, _ := regexp.Compile(regex)
for _, line := range strings.Split(blocks[1], "\n") {
if r.MatchString(line) {
s++
}
}
return
}
//resolveRulesRegex resolve a rule to a regex string (follow a loop max 20 times)
func resolveRulesRegex(ruleID int, rules map[int]string) (resolvedRule string) {
if cache[ruleID] != "" {
return cache[ruleID]
}
if strings.HasPrefix(rules[ruleID], "\"") {
return strings.Trim(rules[ruleID], "\"")
}
regex := "(:?"
orBlocks := strings.Split(rules[ruleID], " | ")
for i, ruleBlock := range orBlocks {
if i != 0 {
regex += "|"
}
for _, otherRules := range strings.Split(ruleBlock, " ") {
otherRulesNum, _ := strconv.Atoi(otherRules)
if otherRulesNum == ruleID {
loopDetect[ruleID]++
if loopDetect[ruleID] > 20 {
continue
}
}
regex += resolveRulesRegex(otherRulesNum, rules)
}
}
regex += ")"
cache[ruleID] = regex
return regex
}