-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2.hs
89 lines (60 loc) · 1.76 KB
/
2.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
import Text.Parsec hiding (Line)
import Text.Parsec.String
import Data.List (sort, group)
import Data.Either (lefts, rights)
main :: IO ()
main = do
input <- lines <$> readFile "input2"
let (parseReport, result1) = solve valid input
(_ , result2) = solve valid2 input
putStrLn parseReport
print result1
print result2
type ParserReport = String
type Line = (Char, Int, Int, String)
solve :: (Line -> Bool) -> [String] -> (ParserReport, Int)
solve policy input =
let lines = map (parse parserLine "") input
parseReport = case lefts lines of
[] -> "Parse OK"
xs -> "Warning! Could not parse " ++ (show $ length xs) ++ " lines"
num = length . filter policy $ rights lines
in (parseReport, num)
nat :: Parser Int
nat = (\x -> read x :: Int) <$> many1 digit
parserLine :: Parser Line
parserLine = do
x <- nat
char '-'
y <- nat
space
c <- letter
char ':'
space
password <- many1 letter
spaces
return (c, x, y, password)
valid :: Line -> Bool
valid (c, low, high, password) =
let maybeFreq = lookup c $ charFrequencyList password
in case maybeFreq of
Just freq -> freq `inRange` (low, high)
Nothing -> False
-- part 2
charFrequencyList :: String -> [(Char,Int)]
charFrequencyList = map (\xs -> (head xs, length xs)) . group . sort
inRange :: Int -> (Int, Int) -> Bool
inRange x (low, high) = low <= x && x <= high
valid2 :: Line -> Bool
valid2 (c, pos1, pos2, pw) =
let mx = lookup pos1 $ zip [1..] pw
my = lookup pos2 $ zip [1..] pw
mc = Just c
in (mc == mx) `xor` (mc == my)
xor :: Bool -> Bool -> Bool
xor a b = ( a || b ) && not ( a && b )
testInput :: [String]
testInput =
["1-3 a: abcde"
,"1-3 b: cdefg"
,"2-9 c: ccccccccc"]