Created
December 4, 2020 06:23
-
-
Save object/c51799df803e8f4210a0d1a2bc435cb7 to your computer and use it in GitHub Desktop.
AdventOfCode 2020, December 4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| open System | |
| open System.IO | |
| let input = | |
| File.ReadAllLines("input04.txt") | |
| |> Seq.toList | |
| let expected_fields_without_country = ["byr"; "iyr"; "eyr"; "hgt"; "hcl"; "ecl"; "pid"] |> Set.ofList | |
| let expected_fields = expected_fields_without_country |> Set.add "cid" | |
| let isNumberBetween min max (str:string) = | |
| match Int32.TryParse str with | |
| | true, n -> n >= min && n <= max | |
| | _ -> false | |
| let isValidField name (value:string) = | |
| match name with | |
| | "byr" -> isNumberBetween 1920 2002 value | |
| | "iyr" -> isNumberBetween 2010 2020 value | |
| | "eyr" -> isNumberBetween 2020 2030 value | |
| | "hgt" -> if value.EndsWith "cm" then isNumberBetween 150 193 (value.Substring(0,value.Length-2)) else if value.EndsWith "in" then isNumberBetween 59 76 (value.Substring(0,value.Length-2)) else false | |
| | "hcl" -> value.Length = 7 && value.[0] = '#' && value |> Seq.skip 1 |> Seq.forall (fun x -> x >= '0' && x <= '9' || x >= 'a' && x <= 'f') | |
| | "ecl" -> ["amb"; "blu"; "brn"; "gry"; "grn"; "hzl"; "oth"] |> List.contains value | |
| | "pid" -> value.Length = 9 && value |> Seq.forall Char.IsDigit | |
| | "cid" -> true | |
| | _ -> false | |
| let passports = | |
| input | |
| |> List.fold (fun (all_passports,current_passport) (line:string) -> | |
| if String.IsNullOrEmpty line then | |
| current_passport :: all_passports,Map.empty | |
| else | |
| let fields = line.Split(' ') |> Array.map (fun x -> x.Split(':')) | |
| let current_passport = fields |> Array.fold (fun acc field -> acc |> Map.add field.[0] field.[1]) current_passport | |
| all_passports,current_passport | |
| ) (List.empty,Map.empty) | |
| |> fun (xs,x) -> if not (x |> Map.isEmpty) then x :: xs else xs | |
| let hasRequiredFields passport = | |
| passport | |
| |> Map.toList | |
| |> List.map fst | |
| |> Set.ofList | |
| |> fun x -> x = expected_fields || x = expected_fields_without_country | |
| let hasValidFields passport = | |
| passport | |
| |> Map.toList | |
| |> List.fold (fun acc field -> if acc then acc && isValidField (fst field) (snd field) else false) true | |
| let answer = | |
| passports | |
| |> List.filter (fun passport -> hasRequiredFields passport && hasValidFields passport) | |
| |> List.length |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment