Tweaked solution 9 a bit, to check all approaches are finding the same set of items
[summerofcode2018soln.git] / src / task5 / task5-lines.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_all <- TIO.readFile "data/05-instructions.txt"
12 let text = T.lines text_all
13 let uncommented = map deComment text
14 let expanded = map expand uncommented
15 print $ countNonSpace uncommented
16 print $ countNonSpace expanded
17 -- TIO.writeFile "data/05-output.ppm" $ T.unlines expanded
18
19
20 countNonSpace :: [Text] -> Int
21 countNonSpace = sum . map (T.length . T.filter (\c -> not (isSpace c)))
22
23
24 -- Remove comments
25 deComment :: Text -> Text
26 deComment text = deComment' (extractFirstComment text) text
27
28 -- If there are no comments, return the text as-is
29 -- If there is a first comment, decomment the rest
30 deComment' :: Maybe (Text, Text) -> Text -> Text
31 deComment' Nothing text = text
32 deComment' (Just (prefix, suffix)) _ = prefix `T.append` (deComment suffix)
33
34 -- Monad notation to string togeether all the Maybes
35 extractFirstComment :: Text -> Maybe (Text, Text)
36 extractFirstComment text =
37 do (prefix, commentSuffix) <- maybeBreakOn "<" text
38 (_, suffix) <- maybeBreakOn ">" commentSuffix
39 return (prefix, suffix)
40
41
42 -- Expand compression
43 expand :: Text -> Text
44 expand text = expand' (extractFirstExpander text) text
45
46 -- If there are no compression markers, return the text
47 -- If there's one, expand it, and try again.
48 expand' :: Maybe (Text, Int, Int, Text) -> Text -> Text
49 expand' Nothing text = text
50 expand' (Just (prefix, expandLen, expandCount, suffix)) _ =
51 expand (expandedPrefix `T.append` suffix)
52 where unexpandedPrefix = T.dropEnd expandLen prefix
53 group = T.takeEnd expandLen prefix
54 expanded = T.replicate expandCount group
55 expandedPrefix = unexpandedPrefix `T.append` expanded
56
57 extractFirstExpander :: Text -> Maybe (Text, Int, Int, Text)
58 extractFirstExpander text =
59 do (prefix, suffix) <- maybeBreakOn ":" text
60 (expanderLenT, suffix') <- maybeBreakOn ":" suffix
61 (expanderCountT, suffix'') <- maybeBreakOn ":" suffix'
62 let expanderLen = read $ T.unpack expanderLenT
63 let expanderCount = read $ T.unpack expanderCountT
64 return (prefix, expanderLen, expanderCount, suffix'')
65
66
67 -- Uses Text.breakOn, but puts the result in a Maybe
68 -- Also drops the needle from the returned suffix.
69 maybeBreakOn :: Text -> Text -> Maybe (Text, Text)
70 maybeBreakOn needle haystack =
71 if T.null suffix
72 then Nothing
73 else Just (prefix, T.drop (T.length needle) suffix)
74 where (prefix, suffix) = T.breakOn needle haystack