-
Notifications
You must be signed in to change notification settings - Fork 0
/
7a.hs
65 lines (51 loc) · 1.71 KB
/
7a.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
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE OverloadedStrings #-}
import Data.Either
import Data.List
import Data.Maybe
import Text.Parsec hiding (count)
import Prelude
main = do
input <- getContents
putStr $ show $ fn $ lines input
type Inner = String
type Outer = String
type Bag = (Outer, [Inner])
type Inversed = (Inner, Outer)
--mirrored gold bags contain 3 light teal bags.
innerBag :: Parsec String () String
innerBag = do
try space
amount <- digit
try space
innerBag <- manyTill anyChar $ try $ string " bag"
optional $ char 's'
choice [char ',', char '.']
return innerBag
outerBag :: Parsec String () String
outerBag = do
outerBag <- manyTill anyChar $ try $ string " bags" -- Note leading space
try $ string " contain"
return outerBag
bagParser :: Parsec String () Bag
bagParser = do
outerBag <- outerBag
innerBags <- many1 innerBag
eof
return (outerBag, innerBags)
-- Make (Outer, [Inners]) to [(Inner, Outer)]
inverseBag :: Bag -> [Inversed]
inverseBag (x, xs) = map (,x) xs
-- Make [(Outer, [Inners])] to [[(Inner, Outer)]]
inverseBags :: [Bag] -> [Inversed]
inverseBags = concatMap inverseBag
-- From a list of strings ('inner'), find a list of strings ('outer')
findParents :: [String] -> [Inversed] -> [String]
findParents xs ys = map snd $ concatMap (\x -> filter ((x ==) . fst) ys) xs
-- From a list of strings ('inner'), find a list of strings ('outer')
-- If there are 'outer' strings, do it again
findParentsRec :: [String] -> [String] -> [Inversed] -> [String]
findParentsRec acc xs ys = case findParents xs ys of
[] -> acc
zs -> findParentsRec (zs ++ acc) zs ys
fn xs = length $ nub $ findParentsRec [] ["shiny gold"] $ inverseBags $ rights $ map (runParser bagParser () "Err") xs