mirror of
https://github.com/mx42/adventofcode.git
synced 2026-01-14 22:09:50 +01:00
58 lines
2.4 KiB
Haskell
58 lines
2.4 KiB
Haskell
module Y2020.Day04 (y20day04) where
|
|
|
|
import Data.Char
|
|
import Data.Maybe
|
|
import Data.List.Split
|
|
import qualified Data.Map as M
|
|
|
|
data RawPassport = RawPassport {
|
|
birth_year :: String
|
|
, issue_year :: String
|
|
, expir_year :: String
|
|
, height :: String
|
|
, hair_color :: String
|
|
, eye_color :: String
|
|
, passport_id :: String
|
|
} deriving (Show)
|
|
|
|
parsePassport :: String -> Maybe RawPassport
|
|
parsePassport input = do
|
|
byr <- M.lookup "byr" mapped
|
|
iyr <- M.lookup "iyr" mapped
|
|
eyr <- M.lookup "eyr" mapped
|
|
hgt <- M.lookup "hgt" mapped
|
|
hcl <- M.lookup "hcl" mapped
|
|
ecl <- M.lookup "ecl" mapped
|
|
pid <- M.lookup "pid" mapped
|
|
return (RawPassport byr iyr eyr hgt hcl ecl pid)
|
|
where mapped = M.fromList $ map (\a -> (a !! 0, a !! 1)) $ map (splitOn ":") $ splitOn " " input
|
|
|
|
allTrue :: [Bool] -> Bool
|
|
allTrue = all (== True)
|
|
|
|
checkDigitInRange :: Int -> Int -> String -> Bool
|
|
checkDigitInRange mini maxi input = allTrue $ map ($ input) [(all (isDigit)), ((>= mini) . read), ((<= maxi) . read)]
|
|
|
|
validatePassport :: RawPassport -> Bool
|
|
validatePassport pass = allTrue [validatePassID, validateBirth, validateIssued, validateExpiration, validateHeight, validateHairColor, validateEyeColor]
|
|
where validateBirth = checkDigitInRange 1920 2002 $ birth_year pass
|
|
validateIssued = checkDigitInRange 2010 2020 $ issue_year pass
|
|
validateExpiration = checkDigitInRange 2020 2030 $ expir_year pass
|
|
validateHeight = not unitAvailable && (correctHeightCm || correctHeightIn)
|
|
where correctHeightCm = checkDigitInRange 150 193 $ (splitOn "cm" (height pass)) !! 0
|
|
correctHeightIn = checkDigitInRange 59 76 $ (splitOn "in" (height pass)) !! 0
|
|
unitAvailable = all (isDigit) (height pass)
|
|
validateHairColor = allTrue $ map ($ hair_color pass) [((== '#') . head), (all (`elem` "0123456789abcdef") . tail), ((== 7) . length)]
|
|
validateEyeColor = (eye_color pass) `elem` ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
|
|
validatePassID = allTrue $ map ($ passport_id pass) [((== 9) . length), (all (isDigit))]
|
|
|
|
y20day04 :: [String] -> (String, String)
|
|
y20day04 input = (part1, part2)
|
|
where part1 = show $ length $ passports
|
|
part2 = show $ length $ validPassports
|
|
passports = concatMap maybeToList $ map parsePassport $ map replaceNL $ splitOn "\n\n" $ unlines input
|
|
replaceNL = map repl
|
|
repl '\n' = ' '
|
|
repl c = c
|
|
validPassports = filter validatePassport passports
|