Day 16: Part 1

Signed-off-by: James Griffin <james@unsupervised.ca>
This commit is contained in:
2020-12-16 11:23:09 -04:00
parent ab1a158f25
commit b633408e52
5 changed files with 450 additions and 3 deletions

131
sixteen/day_sixteen.go Normal file
View File

@@ -0,0 +1,131 @@
package sixteen
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type ticket struct {
values []int
fields []string
}
type constraint struct {
min, max int
}
type ticketScanner struct {
rules map[string][]constraint
me *ticket
nearby []ticket
}
func (ts *ticketScanner) load(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
ts.rules = make(map[string][]constraint)
var rules, myticket bool
scanner := bufio.NewScanner(file)
for scanner.Scan() {
if scanner.Text() == "" {
continue
}
if scanner.Text() == "your ticket:" {
rules = true
continue
}
if !rules {
parts := strings.Split(scanner.Text(), ":")
if len(parts) != 2 {
return fmt.Errorf("Unable to parse rule %s", scanner.Text())
}
ranges := []constraint{}
c := strings.Split(parts[1], " or ")
for _, a := range c {
b := constraint{}
count, err := fmt.Sscanf(a, "%d-%d", &b.min, &b.max)
if count != 2 || err != nil {
return fmt.Errorf("Unable to parse %s", a)
}
ranges = append(ranges, b)
}
ts.rules[parts[0]] = ranges
continue
}
if scanner.Text() == "nearby tickets:" {
myticket = true
continue
}
if !myticket {
t := &ticket{}
values := strings.Split(scanner.Text(), ",")
for _, v := range values {
intValue, err := strconv.Atoi(v)
if err != nil {
return err
}
t.values = append(t.values, intValue)
}
ts.me = t
continue
}
t := ticket{}
values := strings.Split(scanner.Text(), ",")
for _, v := range values {
intValue, err := strconv.Atoi(v)
if err != nil {
return err
}
t.values = append(t.values, intValue)
}
ts.nearby = append(ts.nearby, t)
}
return nil
}
func (ts *ticketScanner) nearbyErrorRate() int {
errorRate := 0
for _, t := range ts.nearby {
for _, value := range t.values {
valid := false
for _, rule := range ts.rules {
for _, r := range rule {
if value >= r.min && value <= r.max {
valid = true
break
}
}
if valid {
break
}
}
if !valid {
errorRate += value
}
}
}
return errorRate
}
// PartOne What is my nearby ticket scanning error rate
func PartOne() string {
ts := ticketScanner{}
if err := ts.load("sixteen/input.txt"); err != nil {
return err.Error()
}
return fmt.Sprintf("The nearby scanning error rate is %d", ts.nearbyErrorRate())
}