Day 19: Part 1 and 2
Signed-off-by: James Griffin <james@unsupervised.ca>
This commit is contained in:
139
nineteen/day_nineteen.go
Normal file
139
nineteen/day_nineteen.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package nineteen
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type rule struct {
|
||||
matches string
|
||||
composedOf [][]int
|
||||
}
|
||||
|
||||
type satellite struct {
|
||||
rules map[int]rule
|
||||
messages []string
|
||||
}
|
||||
|
||||
func (s *satellite) load(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
s.rules = map[int]rule{}
|
||||
scanner := bufio.NewScanner(file)
|
||||
messages := false
|
||||
for scanner.Scan() {
|
||||
if !messages {
|
||||
if scanner.Text() == "" {
|
||||
messages = true
|
||||
continue
|
||||
}
|
||||
|
||||
ruleSplit := strings.Split(scanner.Text(), ": ")
|
||||
ruleKey, err := strconv.Atoi(ruleSplit[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r := rule{}
|
||||
|
||||
if strings.Contains(ruleSplit[1], "\"a\"") {
|
||||
r.matches = "a"
|
||||
} else if strings.Contains(ruleSplit[1], "\"b\"") {
|
||||
r.matches = "b"
|
||||
} else {
|
||||
options := strings.Split(ruleSplit[1], " | ")
|
||||
for _, o := range options {
|
||||
m := []int{}
|
||||
rules := strings.Split(o, " ")
|
||||
for _, r := range rules {
|
||||
t, err := strconv.Atoi(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m = append(m, t)
|
||||
}
|
||||
r.composedOf = append(r.composedOf, m)
|
||||
}
|
||||
}
|
||||
|
||||
s.rules[ruleKey] = r
|
||||
continue
|
||||
}
|
||||
|
||||
s.messages = append(s.messages, scanner.Text())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *satellite) match(r int, input string) (bool, int) {
|
||||
if len(input) == 0 {
|
||||
return false, 0
|
||||
}
|
||||
|
||||
rule := s.rules[r]
|
||||
|
||||
if rule.matches == string(input[0]) {
|
||||
return true, 1
|
||||
}
|
||||
|
||||
matchedChars := 0
|
||||
for i := 0; i < len(rule.composedOf); i++ {
|
||||
matchedChars = 0
|
||||
valid := true
|
||||
if len(rule.composedOf[i]) > len(input) {
|
||||
continue
|
||||
}
|
||||
for _, sr := range rule.composedOf[i] {
|
||||
match, count := s.match(sr, input[matchedChars:])
|
||||
matchedChars += count
|
||||
if !match {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if valid {
|
||||
return true, matchedChars
|
||||
}
|
||||
}
|
||||
|
||||
return false, matchedChars
|
||||
}
|
||||
|
||||
func (s *satellite) messageCount(r int) (count int) {
|
||||
for _, m := range s.messages {
|
||||
match, length := s.match(r, m)
|
||||
if match && length == len(m) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// PartOne How many messages match message 0
|
||||
func PartOne() string {
|
||||
s := satellite{}
|
||||
if err := s.load("nineteen/input.txt"); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("There are %d messages that match rule 0", s.messageCount(0))
|
||||
}
|
||||
|
||||
// PartTwo How many messages match message 0 with alternate rules
|
||||
func PartTwo() string {
|
||||
s := satellite{}
|
||||
if err := s.load("nineteen/input2.txt"); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return fmt.Sprintf("There are %d messages that match rule 0", s.messageCount(0))
|
||||
}
|
Reference in New Issue
Block a user