package main import ( "bufio" "fmt" "os" "regexp" "strconv" "strings" ) var validFields = []string{ "byr", // Birth Year "iyr", // Issue Year "eyr", // Expiration Year "hgt", // Height "hcl", // Hair Color "ecl", // Eye Color "pid", // Passport ID "cid", // Country ID } var requiredFields = []string{"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"} var validEyeColors = []string{"amb", "blu", "brn", "gry", "grn", "hzl", "oth"} // Passport ... type Passport map[string]string func stringInSlice(slice []string, str string) bool { for _, s := range slice { if s == str { return true } } return false } // HasAllFields checks that all requried fields are present. func (p Passport) HasAllFields() bool { for _, s := range requiredFields { if _, ok := p[s]; !ok { return false } } return true } // IsValid validates a passport. func (p Passport) IsValid() bool { for k, v := range p { switch k { case "byr": val, _ := strconv.Atoi(v) if !(val >= 1920 && val <= 2002) { return false } case "iyr": val, _ := strconv.Atoi(v) if !(val >= 2010 && val <= 2020) { return false } case "eyr": val, _ := strconv.Atoi(v) if !(val >= 2020 && val <= 2030) { return false } case "hgt": if len(v) < 3 { return false } unit := v[len(v)-2:] measurement, _ := strconv.Atoi(v[:len(v)-2]) switch unit { case "cm": if !(measurement >= 150 && measurement <= 193) { return false } case "in": if !(measurement >= 59 && measurement <= 76) { return false } default: return false } case "hcl": if len(v) != 7 { return false } matched, _ := regexp.MatchString("[a-fA-F0-9]+", v[1:]) if !matched { return false } case "ecl": if !stringInSlice(validEyeColors, v) { return false } case "pid": if len(v) != 9 { return false } matched, _ := regexp.MatchString(`^\d+$`, v[1:]) if !matched { return false } default: } } return true } func (p Passport) String() string { var result strings.Builder fmt.Fprintf( &result, `╭─────────────────────────────────────────╮ │ Passport Card │ │ +-------+ Issuing Country Passport ID │ │ | /-\ | %03s %09s │ │ | \-/ | │ │ | /-u-\ | Issued Expires │ │ +-------+ %04s %04s │ │ │ │ Height Hair Color Eye Color │ │ %05s %07s %03s │ │ Birth Year │ │ %04s │ ╰─────────────────────────────────────────╯`, p["cid"], p["pid"], p["iyr"], p["eyr"], p["hgt"], p["hcl"], p["ecl"], p["byr"], ) return result.String() } // Task1 ... func Task1(input []Passport) int { var result int for _, i := range input { if i.HasAllFields() { result++ } } return result } // Task2 ... func Task2(input []Passport) int { var result int for _, i := range input { if i.HasAllFields() && i.IsValid() { result++ } } return result } func main() { var input []Passport file, _ := os.Open("input.txt") scanner := bufio.NewScanner(file) p := Passport{} for scanner.Scan() { data := strings.Split(scanner.Text(), " ") if len(data) == 1 && data[0] == "" { input = append(input, p) p = Passport{} continue } for _, d := range data { kv := strings.Split(d, ":") if stringInSlice(validFields, kv[0]) { p[kv[0]] = kv[1] } } } input = append(input, p) file.Close() result := Task1(input) fmt.Printf("Task 1: %d\n", result) result = Task2(input) fmt.Printf("Task 2: %d\n", result) }