Compare commits

...

3 Commits

  1. 3
      .gitignore
  2. 2
      AdventOfCode2020.cabal
  3. 2
      Main.hs
  4. 1009
      input/day4
  5. 158
      src/Day4.hs

3
.gitignore vendored

@ -23,3 +23,6 @@ cabal.project.local~
.HTF/
.ghc.environment.*
# vscode
.vscode

@ -17,7 +17,7 @@ maintainer: gael@depreeuw.dev
extra-source-files: CHANGELOG.md, README.md
library
exposed-modules: Day1, Day2, Day3
exposed-modules: Day1, Day2, Day3, Day4
-- other-modules:
-- other-extensions:
build-depends: base ^>=4.13.0.0

@ -3,9 +3,11 @@ module Main where
import Day1 (day1)
import Day2 (day2)
import Day3 (day3)
import Day4 (day4)
main :: IO ()
main = do
day1
day2
day3
day4

File diff suppressed because it is too large Load Diff

@ -0,0 +1,158 @@
{-# LANGUAGE OverloadedStrings #-}
module Day4 (day4) where
import Control.Applicative ((<|>))
import Control.Monad (void)
import qualified Data.Attoparsec.Text as P
import qualified Data.Map as M
import Data.Maybe (catMaybes)
import qualified Data.Text as T
data Height = CM Integer | IN Integer deriving (Show, Eq)
data EyeColour = AMB | BLU | BRN | GRY | GRN | HZL | OTH deriving (Show, Eq)
type BYR = Either String Integer
type IYR = Either String Integer
type EYR = Either String Integer
type HGT = Either String Height
type HCL = Either String String
type ECL = Either String EyeColour
type PID = Either String Integer
type CID = T.Text
data Passport = Passport
{ byr :: BYR,
iyr :: IYR,
eyr :: EYR,
hgt :: HGT,
hcl :: HCL,
ecl :: ECL,
pid :: PID,
cid :: Maybe CID -- Definitely not a hack!
}
deriving (Eq, Show)
parserPair :: P.Parser (T.Text, T.Text)
parserPair = do
key <- P.count 3 P.letter
_ <- P.char ':'
value <- P.takeWhile1 (P.inClass "a-zA-Z0-9#")
return (T.pack key, value)
parserEntry :: P.Parser (M.Map T.Text T.Text)
parserEntry = M.fromList <$> parserPair `P.sepBy` (void P.space <|> P.endOfLine)
parseBYR :: T.Text -> BYR
parseBYR s = do
n <- P.eitherResult $ P.parse (P.count 4 P.digit) s
let n' = read n
if n' >= 1920 && n' <= 2002 then Right n' else Left (T.unpack s)
parseIYR :: T.Text -> IYR
parseIYR s = do
n <- P.eitherResult $ P.parse (P.count 4 P.digit) s
let n' = read n
if n' >= 2010 && n' <= 2020 then Right n' else Left (T.unpack s)
parseEYR :: T.Text -> EYR
parseEYR s = do
n <- P.eitherResult $ P.parse (P.count 4 P.digit) s
let n' = read n
if n' >= 2020 && n' <= 2030 then Right n' else Left (T.unpack s)
parseCM :: P.Parser Height
parseCM = do
n <- P.count 3 P.digit
_ <- P.string "cm"
let n' = read n
if n' >= 150 && n' <= 193
then return $ CM n'
else fail n
parseIN :: P.Parser Height
parseIN = do
n <- P.count 2 P.digit
_ <- P.string "in"
let n' = read n
if n' >= 59 && n' <= 76
then return $ IN n'
else fail n
parseHGT :: T.Text -> HGT
parseHGT s = P.eitherResult $ P.parse (parseCM <|> parseIN) s
parseHCL :: T.Text -> HCL
parseHCL s =
let p = P.char '#' *> P.count 6 (P.satisfy (P.inClass "a-f0-9"))
in P.eitherResult $ P.parse p s
parseECL :: T.Text -> ECL
parseECL s = do
let pAMB = AMB <$ P.string "amb"
pBLU = BLU <$ P.string "blu"
pBRN = BRN <$ P.string "brn"
pGRY = GRY <$ P.string "gry"
pGRN = GRN <$ P.string "grn"
pHZL = HZL <$ P.string "hzl"
pOTH = OTH <$ P.string "oth"
p = pAMB <|> pBLU <|> pBRN <|> pGRY <|> pGRN <|> pHZL <|> pOTH
in P.eitherResult $ P.parse p s
parsePID :: T.Text -> PID
parsePID s = fmap read (P.parseOnly (P.count 9 P.digit <* P.endOfInput) s)
fromMap :: M.Map T.Text T.Text -> Maybe Passport
fromMap m = do
byr <- m M.!? "byr"
let byr' = parseBYR byr
iyr <- m M.!? "iyr"
let iyr' = parseIYR iyr
eyr <- m M.!? "eyr"
let eyr' = parseEYR eyr
hgt <- m M.!? "hgt"
let hgt' = parseHGT hgt
hcl <- m M.!? "hcl"
let hcl' = parseHCL hcl
ecl <- m M.!? "ecl"
let ecl' = parseECL ecl
pid <- m M.!? "pid"
let pid' = parsePID pid
return $ Passport byr' iyr' eyr' hgt' hcl' ecl' pid' (m M.!? "cid")
parserPassport :: P.Parser (Maybe Passport)
parserPassport = fromMap <$> parserEntry
parseList :: String -> [Maybe Passport]
parseList s =
let p = parserPassport `P.sepBy` P.endOfLine
in case P.parseOnly p (T.pack s) of
Left s -> error (show s)
Right r -> r
validatePassport :: Passport -> Bool
validatePassport (Passport (Left _) _ _ _ _ _ _ _) = False
validatePassport (Passport _ (Left _) _ _ _ _ _ _) = False
validatePassport (Passport _ _ (Left _) _ _ _ _ _) = False
validatePassport (Passport _ _ _ (Left _) _ _ _ _) = False
validatePassport (Passport _ _ _ _ (Left _) _ _ _) = False
validatePassport (Passport _ _ _ _ _ (Left _) _ _) = False
validatePassport (Passport _ _ _ _ _ _ (Left _) _) = False
validatePassport _ = True
day4 :: IO ()
day4 = do
r <- readFile "./input/day4"
putStr "[Day 4-1] # correct: "
let m = catMaybes . parseList $ r
print . length $ m
putStr "[Day 4-2] # more correct: "
print . length . filter validatePassport $ m
Loading…
Cancel
Save