package main import ( "bufio" "fmt" "log" "os" "regexp" "strconv" "strings" ) func checkByr(line string) int { if strings.Contains(line, "byr:") { re := regexp.MustCompile(`byr:(\d{4})`) result := re.FindStringSubmatch(line) if len(result) != 2 { return 0 } byrString := result[1] if byrString == "" { return 0 } byr, err := strconv.ParseInt(byrString, 10, 32) if err != nil { return 0 } if byr >= 1920 && byr <= 2002 { return 1 } } return 0 } func checkIyr(line string) int { if strings.Contains(line, "iyr:") { re := regexp.MustCompile(`iyr:(\d{4})`) result := re.FindStringSubmatch(line) if len(result) != 2 { return 0 } iyrString := result[1] if iyrString == "" { return 0 } iyr, err := strconv.ParseInt(iyrString, 10, 32) if err != nil { return 0 } if iyr >= 2010 && iyr <= 2020 { return 1 } } return 0 } func checkEyr(line string) int { if strings.Contains(line, "eyr:") { re := regexp.MustCompile(`eyr:(\d{4})`) result := re.FindStringSubmatch(line) if len(result) != 2 { return 0 } eyrString := result[1] if eyrString == "" { return 0 } eyr, err := strconv.ParseInt(eyrString, 10, 32) if err != nil { return 0 } if eyr >= 2020 && eyr <= 2030 { return 1 } } return 0 } func checkHgt(line string) int { if strings.Contains(line, "hgt:") { re := regexp.MustCompile(`hgt:(\d+)(\w{2})`) result := re.FindStringSubmatch(line) if len(result) != 3 { return 0 } hgtString := result[1] if hgtString == "" { return 0 } tp := result[2] if tp == "" { return 0 } hgt, err := strconv.ParseInt(hgtString, 10, 32) if err != nil { return 0 } switch tp { case "cm": if hgt >= 150 && hgt <= 193 { return 1 } case "in": if hgt >= 59 && hgt <= 76 { return 1 } } } return 0 } func checkHcl(line string) int { if strings.Contains(line, "hcl:#") { re := regexp.MustCompile(`hcl:#([0-9a-f]{6})`) result := re.FindStringSubmatch(line) if len(result) != 2 { return 0 } hcl := result[1] if hcl != "" { return 1 } } return 0 } var eyeColors = []string{"amb", "blu", "brn", "gry", "grn", "hzl", "oth"} func checkEcl(line string) int { if strings.Contains(line, "ecl:") { re := regexp.MustCompile(`ecl:(\w{3})`) result := re.FindStringSubmatch(line) if len(result) != 2 { return 0 } ecl := result[1] if ecl == "" { return 0 } for _, color := range eyeColors { if color == ecl { return 1 } } } return 0 } func checkPid(line string) int { if strings.Contains(line, "pid:") { re := regexp.MustCompile(`pid:(\d+)`) result := re.FindStringSubmatch(line) if len(result) != 2 { return 0 } pid := result[1] if pid == "" { return 0 } if len(pid) != 9 { return 0 } _, err := strconv.ParseInt(pid, 10, 32) if err == nil { return 1 } } return 0 } func getChecks() map[string]func(string) int { toCheck := make(map[string]func(string) int) toCheck["byr:"] = checkByr toCheck["iyr:"] = checkIyr toCheck["eyr:"] = checkEyr toCheck["hgt:"] = checkHgt toCheck["hcl:"] = checkHcl toCheck["ecl:"] = checkEcl toCheck["pid:"] = checkPid return toCheck } func performCheck(line string, name string, check func(string) int) (int, int) { check1 := 0 check2 := 0 if strings.Contains(line, name) { check1 = 1 check2 = check(line) } return check1, check2 } func checkLine(line string, toCheck map[string]func(string) int) (int, int) { checks1 := 0 checks2 := 0 for name, check := range toCheck { check1, check2 := performCheck(line, name, check) checks1 += check1 checks2 += check2 } return checks1, checks2 } func countChecks(line string, toCheck map[string]func(string) int, valid1 *int, valid2 *int) { check1, check2 := checkLine(line, toCheck) if check1 == 7 { *valid1++ } if check2 == 7 { *valid2++ } } func main() { if len(os.Args) < 2 { log.Fatal("You need to specify a file!") } file, err := os.Open(os.Args[1]) if err != nil { log.Fatalf("failed to open") } var ( valid1, valid2 int text string ) toCheck := getChecks() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() if line == "" { countChecks(text, toCheck, &valid1, &valid2) text = "" continue } text += line + " " } if err := scanner.Err(); err != nil { log.Println(err) } countChecks(text, toCheck, &valid1, &valid2) fmt.Println("Part1: ", valid1) fmt.Println("Part2: ", valid2) }