Day 4.
parent
421b1a4b5e
commit
1360b2cc63
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,98 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fields := []string{
|
||||
"byr",
|
||||
"iyr",
|
||||
"eyr",
|
||||
"hgt",
|
||||
"hcl",
|
||||
"ecl",
|
||||
"pid",
|
||||
"cid",
|
||||
}
|
||||
optionalFields := []string{
|
||||
"cid",
|
||||
}
|
||||
|
||||
f, err := os.Open("input")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
validPasses := 0
|
||||
currentPassValues := map[string]string{}
|
||||
currentPassIsInvalid := false
|
||||
r := bufio.NewReader(f)
|
||||
// log.Println("=== New pass ===")
|
||||
for {
|
||||
line, err := r.ReadString('\n')
|
||||
if err != io.EOF && err != nil {
|
||||
panic(nil)
|
||||
}
|
||||
if err == io.EOF {
|
||||
line = ""
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
if len(currentPassValues) <= 0 && err == io.EOF {
|
||||
break
|
||||
}
|
||||
if len(currentPassValues) <= 0 && len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(currentPassValues) > 0 && (err == io.EOF || len(line) == 0) {
|
||||
// Check if all required fields can be found
|
||||
b:
|
||||
for _, fieldName := range fields {
|
||||
if _, ok := currentPassValues[fieldName]; !ok {
|
||||
// field is missing
|
||||
for _, optionalFieldName := range optionalFields {
|
||||
if optionalFieldName == fieldName {
|
||||
// skip this field for check
|
||||
log.Printf("-- %s is missing (optional)", fieldName)
|
||||
break b
|
||||
}
|
||||
}
|
||||
log.Printf("-- %s is missing", fieldName)
|
||||
currentPassIsInvalid = true
|
||||
break b
|
||||
}
|
||||
}
|
||||
|
||||
if currentPassIsInvalid {
|
||||
log.Println("** INVALID", currentPassValues)
|
||||
} else {
|
||||
log.Println("** VALID", currentPassValues)
|
||||
validPasses++
|
||||
}
|
||||
|
||||
// log.Println("=== New pass ===")
|
||||
currentPassValues = map[string]string{}
|
||||
currentPassIsInvalid = false
|
||||
}
|
||||
|
||||
if !currentPassIsInvalid {
|
||||
passFields := strings.Fields(line)
|
||||
for _, field := range passFields {
|
||||
fieldSplit := strings.SplitN(field, ":", 2)
|
||||
fieldName := fieldSplit[0]
|
||||
fieldValue := fieldSplit[1]
|
||||
// log.Printf("<- %s %s\n", fieldName, fieldValue)
|
||||
if _, ok := currentPassValues[fieldName]; ok {
|
||||
currentPassIsInvalid = true
|
||||
log.Println("-- dupe:", fieldName)
|
||||
}
|
||||
currentPassValues[fieldName] = fieldValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("%d passes valid\n", validPasses)
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func and(f ...func(string) bool) func(string) bool {
|
||||
return func(s string) bool {
|
||||
for _, fs := range f {
|
||||
if !fs(s) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func or(f ...func(string) bool) func(string) bool {
|
||||
return func(s string) bool {
|
||||
for _, fs := range f {
|
||||
if fs(s) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func rx(regex string) func(string) bool {
|
||||
rx := regexp.MustCompile(regex)
|
||||
return rx.MatchString
|
||||
}
|
||||
|
||||
func numrange(min int, max int) func(string) bool {
|
||||
rx := regexp.MustCompile(`\d+`)
|
||||
return func(val string) bool {
|
||||
n := rx.FindString(val)
|
||||
num, err := strconv.Atoi(n)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if num < min || num > max {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func unit(unit string, min int, max int) func(string) bool {
|
||||
rxc := rx(fmt.Sprintf(`^\d+%s$`, unit))
|
||||
return and(rxc, numrange(min, max))
|
||||
}
|
||||
|
||||
func digitsOnly(digits int) func(string) bool {
|
||||
return rx(fmt.Sprintf(`^\d{%d}$`, digits))
|
||||
}
|
||||
|
||||
func digits(digits int, min int, max int) func(string) bool {
|
||||
rxc := digitsOnly(digits)
|
||||
return and(rxc, numrange(min, max))
|
||||
}
|
||||
|
||||
func main() {
|
||||
fields := []string{
|
||||
"byr",
|
||||
"iyr",
|
||||
"eyr",
|
||||
"hgt",
|
||||
"hcl",
|
||||
"ecl",
|
||||
"pid",
|
||||
"cid",
|
||||
}
|
||||
validation := map[string]func(val string) bool{
|
||||
"byr": digits(4, 1920, 2002),
|
||||
"iyr": digits(4, 2010, 2020),
|
||||
"eyr": digits(4, 2020, 2030),
|
||||
"hgt": or(unit("cm", 150, 193), unit("in", 59, 76)),
|
||||
"hcl": rx(`^#[0-9a-f]{6}$`),
|
||||
"ecl": rx(`^(amb|blu|brn|gry|grn|hzl|oth)$`),
|
||||
"pid": digitsOnly(9),
|
||||
}
|
||||
optionalFields := []string{
|
||||
"cid",
|
||||
}
|
||||
|
||||
f, err := os.Open("input")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
validPasses := 0
|
||||
currentPassValues := map[string]string{}
|
||||
currentPassIsInvalid := false
|
||||
r := bufio.NewReader(f)
|
||||
// log.Println("=== New pass ===")
|
||||
for {
|
||||
line, err := r.ReadString('\n')
|
||||
if err != io.EOF && err != nil {
|
||||
panic(nil)
|
||||
}
|
||||
if err == io.EOF {
|
||||
line = ""
|
||||
}
|
||||
line = strings.TrimSpace(line)
|
||||
if len(currentPassValues) <= 0 && err == io.EOF {
|
||||
break
|
||||
}
|
||||
if len(currentPassValues) <= 0 && len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
if len(currentPassValues) > 0 && (err == io.EOF || len(line) == 0) {
|
||||
// Check if all required fields can be found
|
||||
b:
|
||||
for _, fieldName := range fields {
|
||||
if fieldValue, ok := currentPassValues[fieldName]; !ok {
|
||||
// field is missing
|
||||
for _, optionalFieldName := range optionalFields {
|
||||
if optionalFieldName == fieldName {
|
||||
// skip this field for check
|
||||
log.Printf("-- %s is missing (optional)", fieldName)
|
||||
break b
|
||||
}
|
||||
}
|
||||
log.Printf("-- %s is missing", fieldName)
|
||||
currentPassIsInvalid = true
|
||||
break b
|
||||
} else if validator, ok := validation[fieldName]; ok {
|
||||
if !validator(fieldValue) {
|
||||
log.Printf("-- %s (%s) failed validation", fieldName, fieldValue)
|
||||
currentPassIsInvalid = true
|
||||
break b
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentPassIsInvalid {
|
||||
log.Println("** INVALID", currentPassValues)
|
||||
} else {
|
||||
log.Println("** VALID", currentPassValues)
|
||||
validPasses++
|
||||
}
|
||||
|
||||
// log.Println("=== New pass ===")
|
||||
currentPassValues = map[string]string{}
|
||||
currentPassIsInvalid = false
|
||||
}
|
||||
|
||||
if !currentPassIsInvalid {
|
||||
passFields := strings.Fields(line)
|
||||
for _, field := range passFields {
|
||||
fieldSplit := strings.SplitN(field, ":", 2)
|
||||
fieldName := fieldSplit[0]
|
||||
fieldValue := fieldSplit[1]
|
||||
// log.Printf("<- %s %s\n", fieldName, fieldValue)
|
||||
if _, ok := currentPassValues[fieldName]; ok {
|
||||
currentPassIsInvalid = true
|
||||
log.Println("-- dupe:", fieldName)
|
||||
}
|
||||
currentPassValues[fieldName] = fieldValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("%d passes valid\n", validPasses)
|
||||
}
|
Loading…
Reference in New Issue