-
Notifications
You must be signed in to change notification settings - Fork 0
/
day4.hs
140 lines (119 loc) · 5.36 KB
/
day4.hs
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
{-# LANGUAGE ApplicativeDo #-}
import Data.List
import Data.Functor
import Control.Applicative
import qualified Data.Set as Set
import Data.List.Split
import Data.Either
import Data.Maybe
import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
import Data.Void
import Control.Monad
import Control.Applicative.Permutations
type Parser = Parsec Void String
sc :: Parser ()
sc = L.space space1 empty empty
lexeme :: Parser a -> Parser a
lexeme = L.lexeme sc
-- ===========================================================================
-- pt. 1
-- ===========================================================================
type DumbPassport = (Maybe String, Maybe String, Maybe String, Maybe String, Maybe String, Maybe String, Maybe String, Maybe String)
entryToDumbPassport = runParser dumbPassportParser ""
dumbPassportParser :: Parser DumbPassport
dumbPassportParser = runPermutation $ do
let tPDN = toPermutationWithDefault Nothing
let arbString = Just <$> manyTill anySingle spaceChar
byr <- tPDN $ lexeme $ string "byr:" *> arbString
iyr <- tPDN $ lexeme $ string "iyr:" *> arbString
eyr <- tPDN $ lexeme $ string "eyr:" *> arbString
hgt <- tPDN $ lexeme $ string "hgt:" *> arbString
hcl <- tPDN $ lexeme $ string "hcl:" *> arbString
ecl <- tPDN $ lexeme $ string "ecl:" *> arbString
pid <- tPDN $ lexeme $ string "pid:" *> arbString
cid <- tPDN $ lexeme $ string "cid:" *> arbString
pure (byr, iyr, eyr, hgt, hcl, ecl, pid, cid)
checkDumbPassport ((Just _),(Just _),(Just _),(Just _),(Just _),(Just _),(Just _),_) = True
checkDumbPassport _ = False
-- ===========================================================================
-- pt. 2
-- ===========================================================================
type BirthYear = Integer
type IssueYear = Integer
type ExpirationYear = Integer
data Height = Cm Integer | In Integer deriving Show
type HairColor = Integer
type EyeColor = String
type PassportID = Integer
type CountryID = String --expected Integer later
data Passport = P BirthYear IssueYear ExpirationYear
Height HairColor EyeColor PassportID
(Maybe CountryID) deriving Show
entryToPassport = runParser passportParser ""
--checking is external here because
passportParser :: Parser Passport
passportParser = runPermutation $ do
let tPDN = toPermutationWithDefault Nothing
let tP = toPermutation
-- thanks CharlesFrayne
let ensure lbl pred parser = parser >>= (\x -> if pred x then pure x else parseError (FancyError 0 $ Set.singleton $ ErrorFail lbl))
let bounds a b x = x >= a && x <= b
let cnum a b = ensure ("numeric value out of range: " ++ show a ++ "-" ++ show b) (bounds a b)
let arbString = Just <$> manyTill anySingle spaceChar
let decimal = L.decimal
let hexadecimal = L.hexadecimal
let number = decimal <|> hexadecimal
let pidCheck = (count 9 digitChar) *> spaceChar
let heightHelper =
let heightHelper' (Cm a) = bounds 150 193 a
heightHelper' (In a) = bounds 59 76 a
in ensure "Height outside type bounds" heightHelper'
--strictly lowercase hex so no hexDigitChar in case
let hclCheck = (count 6 $ choice $ (digitChar):(char <$> ['a'..'f'])) *> spaceChar
let ecls = choice $ string <$> ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
--Input contained no years with evil leading zeroes to trip these up
byr <- tP $ lexeme $ string "byr:" *> (cnum 1920 2002 decimal)
iyr <- tP $ lexeme $ string "iyr:" *> (cnum 2010 2020 decimal)
eyr <- tP $ lexeme $ string "eyr:" *> (cnum 2020 2030 decimal)
hgt <- tP $ lexeme $ string "hgt:" *> (heightHelper $ decimal <**> ((string "in" $> In) <|> (string "cm" $> Cm)))
hcl <- tP $ lexeme $ string "hcl:#" *> lookAhead hclCheck *> hexadecimal
ecl <- tP $ lexeme $ string "ecl:" *> ecls
pid <- tP $ lexeme $ string "pid:" *> lookAhead pidCheck *> decimal
cid <- tPDN $ lexeme $ string "cid:" *> arbString --number expected eventually
pure (P byr iyr eyr hgt hcl ecl pid cid)
main = do
f <- readFile "inputs/day4.txt"
let ls = lines f
let entries = (++" ") . concat . intersperse " " <$> splitOn [""] ls
let dps = (entryToDumbPassport <$> entries)
print $ length $ filter (checkDumbPassport) $ fromRight undefined <$> dps
let ps = (entryToPassport <$> entries)
let pfails = filter (isLeft) ps
let pgoods = filter (isRight) ps
print $ length pgoods
-- ===========================================================================
-- Because it's heavily implied we'll come back to this/extend it,
-- I'll leave these testing gadgets here.
-- ===========================================================================
--putStrLn $ "pfails:" ++ (show $ length pfails)
--putStrLn $ "pgoods:" ++ (show $ length pgoods)
--sequence_ $ putStrLn . errorBundlePretty . fromLeft undefined <$> pfails
--putStrLn $ errorBundlePretty $ fromLeft undefined $ (fails!!0)
--print $ fromRight undefined <$> dps
--
--putStrLn $ errorBundlePretty $ fromLeft undefined $ (pfails!!0)
--putStrLn $ "print $ take 15 ls"
--print $ take 15 ls
--putStrLn $ "print $ take 5 entries"
--print $ take 5 entries
--let t = zip entries (entryToDumbPassport <$> entries)
--let fails = filter (isLeft . snd) t
--print fails
--print $ length fails
--putStrLn "\n\n"
--print $ fst (fails!!0)
--putStrLn $ errorBundlePretty $ fromLeft undefined $ snd $ (fails!!0)
--print entries
--print $ entryToPassport <$> entries