feat: add main code
This commit is contained in:
159
2020/day04/main.go
Normal file
159
2020/day04/main.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseInput(file string) []string {
|
||||||
|
content, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to read input file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
text := string(content)
|
||||||
|
passports := strings.Split(text, "\n\n")
|
||||||
|
|
||||||
|
result := make([]string, 0, len(passports))
|
||||||
|
for _, passport := range passports {
|
||||||
|
passport = strings.TrimSpace(passport)
|
||||||
|
if passport == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
passport = strings.ReplaceAll(passport, "\n", " ")
|
||||||
|
passport = strings.Join(strings.Fields(passport), " ")
|
||||||
|
result = append(result, passport)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func PartOne(data []string) int {
|
||||||
|
count := 0
|
||||||
|
required := []string{"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"}
|
||||||
|
for _, passport := range data {
|
||||||
|
fields := strings.Fields(passport)
|
||||||
|
present := make(map[string]bool)
|
||||||
|
for _, field := range fields {
|
||||||
|
if idx := strings.Index(field, ":"); idx != -1 {
|
||||||
|
present[field[:idx]] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
missing := false
|
||||||
|
for _, field := range required {
|
||||||
|
if !present[field] {
|
||||||
|
missing = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !missing {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func PartTwo(data []string) int {
|
||||||
|
isNumberInRange := func(value string, min, max int, digits int) bool {
|
||||||
|
if len(value) != digits {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(value)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return n >= min && n <= max
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidHeight := func(value string) bool {
|
||||||
|
if len(value) < 3 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
unit := value[len(value)-2:]
|
||||||
|
number := value[:len(value)-2]
|
||||||
|
n, err := strconv.Atoi(number)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if unit == "cm" {
|
||||||
|
return n >= 150 && n <= 193
|
||||||
|
}
|
||||||
|
if unit == "in" {
|
||||||
|
return n >= 59 && n <= 76
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidHairColor := func(value string) bool {
|
||||||
|
if len(value) != 7 || value[0] != '#' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, c := range value[1:] {
|
||||||
|
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidPID := func(value string) bool {
|
||||||
|
if len(value) != 9 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, c := range value {
|
||||||
|
if c < '0' || c > '9' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
validECL := map[string]bool{
|
||||||
|
"amb": true, "blu": true, "brn": true, "gry": true,
|
||||||
|
"grn": true, "hzl": true, "oth": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
required := []string{"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"}
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
for _, passport := range data {
|
||||||
|
fields := map[string]string{}
|
||||||
|
for field := range strings.FieldsSeq(passport) {
|
||||||
|
parts := strings.SplitN(field, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
fields[parts[0]] = parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
passportValidators := map[string]func(string) bool{
|
||||||
|
"byr": func(v string) bool { return isNumberInRange(v, 1920, 2002, 4) },
|
||||||
|
"iyr": func(v string) bool { return isNumberInRange(v, 2010, 2020, 4) },
|
||||||
|
"eyr": func(v string) bool { return isNumberInRange(v, 2020, 2030, 4) },
|
||||||
|
"hgt": isValidHeight,
|
||||||
|
"hcl": isValidHairColor,
|
||||||
|
"ecl": func(v string) bool { return validECL[v] },
|
||||||
|
"pid": isValidPID,
|
||||||
|
}
|
||||||
|
|
||||||
|
valid := true
|
||||||
|
for _, key := range required {
|
||||||
|
value, ok := fields[key]
|
||||||
|
if !ok || !passportValidators[key](value) {
|
||||||
|
valid = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if valid {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := parseInput("input.txt")
|
||||||
|
fmt.Println("Part 1:", PartOne(data))
|
||||||
|
fmt.Println("Part 2:", PartTwo(data))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user