-
Notifications
You must be signed in to change notification settings - Fork 0
/
Preface.hs
183 lines (151 loc) · 4.72 KB
/
Preface.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
module Preface (
module Preface,
satisfy, anySingle, sepBy
) where
import System.Environment
import Text.Printf
import Text.Megaparsec (setInput, anySingle, satisfy, parse, Parsec, eof, sepBy)
import Text.Megaparsec.Char (newline)
import Text.Megaparsec.Char.Lexer (decimal, signed)
import Text.Megaparsec.Error (errorBundlePretty)
import Control.DeepSeq as Preface (
NFData(..)
, ($!!)
, deepseq
, force
)
import Safe as Preface
import Data.Foldable (toList)
import Control.Applicative as Preface
import Control.Monad as Preface
import Control.Exception as Preface
import Control.Concurrent as Preface
import Control.Concurrent.Async as Preface
import Data.Void
import Data.Int as Preface
import Data.Bits as Preface
import Data.Word as Preface
import Data.Bool as Preface
import Data.Char as Preface (Char)
import Data.Maybe as Preface
import Data.Either as Preface
import Data.Complex as Preface
import Data.Function as Preface
import Data.List as Preface
import Data.Tuple as Preface
import Data.Map as Preface (Map)
import Data.Set as Preface (Set)
import Data.Sequence as Preface (Seq)
import Data.IntMap as Preface (IntMap)
import Data.IntSet as Preface (IntSet)
import qualified Data.Text as T
import qualified Data.Set as Set
import qualified Data.Map as Map
-- glguy
-- | Get the input for the given day.
--
-- If a filename is provided in the command line that will be used as the
-- input file.
--
-- If the filename is @-@ the stdin will be used as the input file.
--
-- Otherwise the input text file corresponding to the day number will be used.
getRawInput :: Int {- ^ day number -} -> IO String
getRawInput i =
do args <- getArgs
case args of
[] -> readFile (printf "inputs/input%02d.txt" i)
"-":_ -> getContents
fn:_ -> readFile fn
inputFileName :: Int -> FilePath
inputFileName = printf "inputs/input%02d.txt"
getInputLines :: Int -> IO [String]
getInputLines i = lines <$> getRawInput i
type Parser = Parsec Void String
getParsedInput :: Int -> Parser a -> IO a
getParsedInput i p =
do input <- getRawInput i
case parse p "input" input of
Left e -> fail (errorBundlePretty e)
Right a -> return a
-- | Run a parser with 'parseLines' on the input file.
getParsedLines :: Int -> Parser a -> IO [a]
getParsedLines i p =
do input <- getRawInput i
either fail return (parseLines p input)
-- | Run a parser on each line of the input file. Each line will be parsed
-- in isolation. The parser must consume the whole line.
--
-- >>> parseLines (many anySingle) "12\n34\n"
-- Right ["12","34"]
-- >>> parseLines number "12\n34\n"
-- Right [12,34]
parseLines :: Parser a -> String -> Either String [a]
parseLines p input =
case parse (traverse parse1 (lines input)) "input" input of
Left e -> Left (errorBundlePretty e)
Right a -> Right a
where
parse1 x = setInput x *> p <* eof <* setInput "\n" <* newline
-- | Count the number of elements in a foldable value that satisfy a predicate.
count :: Foldable t => (a -> Bool) -> t a -> Int
count p = foldl' (\acc x -> if p x then acc+1 else acc) 0
-- | Return true when the whole list is comprised of equal elements.
--
-- >>> same [1,1,1]
-- True
-- >>> same []
-- True
-- >>> same [1]
-- True
-- >>> same [1,1,2]
-- False
same :: Foldable t => Eq a => t a -> Bool
same xs = all (head (toList xs) ==) xs
-- | Returns a list of ways to select an element from a list without
-- replacement.
--
-- >>> pickOne []
-- []
-- >>> pickOne [1]
-- [(1,[])]
-- >>> pickOne [1,2,3]
-- [(1,[2,3]),(2,[1,3]),(3,[1,2])]
pickOne :: [a] -> [(a, [a])]
pickOne xs = [ (x, l++r) | (l,x:r) <- zip (inits xs) (tails xs) ]
-- | Parse a signed integral number
number :: Integral a => Parser a
number = signed (return ()) decimal
-- | Implementation of 'nub' that uses 'Ord' for efficiency.
ordNub :: Ord a => [a] -> [a]
ordNub = go Set.empty
where
go _ [] = []
go seen (x:xs)
| Set.member x seen = go seen xs
| otherwise = x : go (Set.insert x seen) xs
-- | Compute the minimum element of a list or return Nothing if it is empty.
--
-- >>> minimumMaybe []
-- Nothing
-- >>> minimumMaybe [2,1,3]
-- Just 1
minimumMaybe :: Ord a => [a] -> Maybe a
minimumMaybe xs
| null xs = Nothing
| otherwise = Just $! minimum xs
-- | Compute the number of occurrences of the elements in a given list.
--
-- >>> cardinality "bababc"
-- fromList [('a',2),('b',3),('c',1)]
cardinality :: Ord a => [a] -> Map.Map a Int
cardinality xs = Map.fromListWith (+) [ (x,1) | x <- xs ]
-- glguy
csv = words . map (\c -> if c==',' then ' ' else c)
uncsv = concat . intersperse ","
tshowln :: Show a => a -> T.Text
tshowln = T.pack . (++"\n") . show
tread :: Read a => T.Text -> a
tread = read . T.unpack
viaEnum :: (Enum a, Enum b) => a -> b
viaEnum = toEnum . fromEnum