Done task 5
[summerofcode2018soln.git] / src / task5 / task5.hs
1 {-# LANGUAGE OverloadedStrings #-}
2
3 import Data.Text (Text)
4 import qualified Data.Text as T
5 import qualified Data.Text.IO as TIO
6 import Data.Char (isSpace)
7
8
9 main :: IO ()
10 main = do
11 text <- TIO.readFile "data/05-instructions.txt"
12 let uncommented = deComment text
13 let expanded = expand uncommented
14 print $ countNonSpace uncommented
15 print $ countNonSpace expanded
16
17
18 countNonSpace :: Text -> Int
19 countNonSpace = T.length . T.filter (\c -> not (isSpace c))
20
21
22 -- Remove comments
23 deComment :: Text -> Text
24 deComment text = deComment' (extractFirstComment text) text
25
26 -- If there are no comments, return the text as-is
27 -- If there is a first comment, decomment the rest
28 deComment' :: Maybe (Text, Text) -> Text -> Text
29 deComment' Nothing text = text
30 deComment' (Just (prefix, suffix)) _ = prefix `T.append` (deComment suffix)
31
32 -- Monad notation to string togeether all the Maybes
33 extractFirstComment :: Text -> Maybe (Text, Text)
34 extractFirstComment text =
35 do (prefix, commentSuffix) <- maybeBreakOn "<" text
36 (_, suffix) <- maybeBreakOn ">" commentSuffix
37 return (prefix, suffix)
38
39
40 -- Expand compression
41 expand :: Text -> Text
42 expand text = expand' (extractFirstExpander text) text
43
44 -- If there are no compression markers, return the text
45 -- If there's one, expand it, and try again.
46 expand' :: Maybe (Text, Int, Int, Text) -> Text -> Text
47 expand' Nothing text = text
48 expand' (Just (prefix, expandLen, expandCount, suffix)) _ =
49 expand (expandedPrefix `T.append` suffix)
50 where unexpandedPrefix = T.dropEnd expandLen prefix
51 group = T.takeEnd expandLen prefix
52 expanded = T.replicate expandCount group
53 expandedPrefix = unexpandedPrefix `T.append` expanded
54
55 extractFirstExpander :: Text -> Maybe (Text, Int, Int, Text)
56 extractFirstExpander text =
57 do (prefix, suffix) <- maybeBreakOn ":" text
58 (expanderLenT, suffix') <- maybeBreakOn ":" suffix
59 (expanderCountT, suffix'') <- maybeBreakOn ":" suffix'
60 let expanderLen = read $ T.unpack expanderLenT
61 let expanderCount = read $ T.unpack expanderCountT
62 return (prefix, expanderLen, expanderCount, suffix'')
63
64
65 -- Uses Text.breakOn, but puts the result in a Maybe
66 -- Also drops the needle from the returned suffix.
67 maybeBreakOn :: Text -> Text -> Maybe (Text, Text)
68 maybeBreakOn needle haystack =
69 if T.null suffix
70 then Nothing
71 else Just (prefix, T.drop (T.length needle) suffix)
72 where (prefix, suffix) = T.breakOn needle haystack