8 import Text => qualified join
10 import Control.Applicative
12 import Text.Parsers.Simple.ParserCombinators
13 from Data.Set import :: Set
14 import qualified Data.Set as DS
16 read :: *File -> [Char]
18 # (ok, c, f) = freadc f
24 # (Right (fields, myticket, nearby)) = parse parseInput (read io)
25 # nearby = filter (not o isEmpty) nearby
26 = (one fields nearby, two fields myticket nearby)
28 one :: [([Char], [Int])] -> ([[Int]] -> Int)
29 one fields = sum o flatten o map (filter \e->not $ isMember e $ flatten $ map snd fields)
31 valid fields = isEmpty o filter \e->not $ isMember e $ flatten $ map snd fields
33 // for every ticket, for every field, every option
34 two :: [([Char], [Int])] [Int] [[Int]] -> Int
35 two fields myticket nearby
36 // Translate to numbers and multiply
37 = prod $ zipWith (\i [s]->if (startsWith ['departure'] s) i 1) myticket
38 // iteratively find all singletons and apply constraint
40 // Transpose and merge all fieldconstraints
41 $ map (\[x:xs]->foldr intersect x xs) $ transpose
42 // Remove all invalid fields
43 $ map (collectConstraints fields)
44 // Remove all invalid tickets
45 $ filter (valid fields) nearby
47 collectConstraints :: [([Char], [Int])] [Int] -> [[[Char]]]
48 collectConstraints fields fs = map collectConstraint fs
50 collectConstraint :: Int -> [[Char]]
51 collectConstraint num = [f\\(f, rng)<-fields | isMember num rng]
53 proc :: [[[Char]]] [[[Char]]] -> [[[Char]]]
54 proc had [[x]:todo] = proc [[x]:map (filter ((<>)x)) had] $ map (filter ((<>)x)) todo
55 proc had [x:todo] = proc [x:had] todo
56 proc had [] = if (any ((<>) 1 o length) had) (proc [] had) had
58 parseInput :: Parser Char ([([Char], [Int])], [Int], [[Int]])
59 parseInput = tuple3 <$> many pField
60 <* pStr ['\nyour ticket:\n'] <*> pSepBy pInt pComma <* pToken '\n'
61 <* pStr ['\nnearby tickets:\n'] <*> pSepBy (pSepBy pInt pComma) (pToken '\n')
63 pField :: Parser Char ([Char], [Int])
64 pField = tuple <$> many (pSatisfy (\c->isAlpha c || c == ' ')) <* pStr [': '] <*> pRange <* pToken '\n'
66 pRange :: Parser Char [Int]
67 pRange = flatten <$> pSepBy ((\x y->[x..y]) <$> pInt <* pToken '-' <*> pInt) (pStr [' or '])
69 pInt :: Parser Char Int
70 pInt = toInt o toString <$> some pDigit
72 pStr :: ([Char] -> Parser Char [Char])
73 pStr = sequence o map pToken