aboutsummaryrefslogtreecommitdiff
path: root/execs/Day04.hs
blob: 04aacbbd044715abb8ae88439f6a83846a3b9e65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
module Main where

import Text.ParserCombinators.Parsec
import Text.Parsec.Char
import Data.Either
import Data.Maybe
import Control.Monad
import Data.List (sortOn)

right (Right a) = a
fields = [ "byr" , "iyr" , "eyr" , "hgt" , "hcl" , "ecl" , "pid" ] 

block = cell `sepBy` oneOf " \n"
cell = do
    tag <- many lower
    char ':'
    rest <- many (alphaNum <|> char '#')
    return (tag, rest)

parseInput :: String -> Either ParseError [(String, String)]
parseInput = parse block "input"

assocGet s (l:ls) = if fst l == s
                       then snd l
                       else assocGet s ls

doCheck :: [(String, String)] -> Bool
doCheck ls = all (isJust . flip lookup ls) fields

checkNum lower up s = p >= lower && p <= up
    where p = read s :: Int
byr = checkNum 1920 2002
iyr = checkNum 2010 2020
eyr = checkNum 2020 2030

parseHeight :: Parser (Int, String)
parseHeight = do
    v <- many1 digit
    unit <- choice $ map string ["cm", "in"]
    return (read v, unit)
hgt s = case parse parseHeight "hgt" s of
          Right (v, "cm") -> v >= 150 && v <= 193
          Right (v, "in") -> v >= 59 && v <= 76
          _ -> False

parseColor = char '#' >> many hexDigit
hcl :: String -> Bool
hcl s = case parse parseColor "hcl" s of
          Right c -> length c == 6
          Left _ -> False


ecl :: String -> Bool
ecl = flip elem ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]

parsePid = replicateM 9 digit
pid :: String -> Bool
pid s = isRight $ parse parsePid "pid" s

doValidity :: [(String, String)] -> Bool
doValidity ls = all ((== True) . ($ ls)) [ byr . assocGet "byr"
                                         , iyr . assocGet "iyr"
                                         , eyr . assocGet "eyr"
                                         , hgt . assocGet "hgt"
                                         , hcl . assocGet "hcl"
                                         , ecl . assocGet "ecl"
                                         , pid . assocGet "pid"
                                         ]

parseLines :: [String] -> [String]
parseLines allLines = unwords first : next
  where (first, rest) = break null allLines
        next = if null rest then [] else parseLines (tail rest)

main :: IO ()
main = do
    n <- parseLines . lines <$> readFile "input/04"
    let blocks = map (right . parseInput) n
    print $ length $ filter (\p -> doCheck p && doValidity p) blocks
    -- mapM_ print $ filter (\p -> doCheck p && doValidity p) $ map (sortOn fst) blocks
    -- print $ length $ filter doCheck blocks
    -- print $ length $ filter (\p -> doCheck p && doValidity p) $ map (sortOn fst) blocks