-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay5.hs
93 lines (79 loc) · 2.46 KB
/
Day5.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
module Day5
( part1
, part2
) where
import Data.ByteString (ByteString)
import Data.Either (fromRight)
import Data.Function (on)
import Data.IntMap (IntMap, empty, fromList, notMember,
(!))
import Data.List (groupBy, sortBy)
import Data.Ord (comparing)
import Data.Word8 (_bar, _comma)
import Helpers.Parsers.ByteString (Parser)
import Text.Megaparsec (eof, manyTill, optional, parse,
sepBy)
import Text.Megaparsec.Byte (char, eol)
import Text.Megaparsec.Byte.Lexer (decimal)
type Rules = IntMap [Int]
type Update = [Int]
parseInput :: Parser (Rules, [Update])
parseInput = do
rules <- buildRules <$> manyTill parseOrder eol
updates <- manyTill parseUpdate eof
return (rules, updates)
parseOrder :: Parser (Int, Int)
parseOrder = do
before <- decimal
char _bar
after <- decimal
eol
return (after, before)
parseUpdate :: Parser [Int]
parseUpdate = do
update <- decimal `sepBy` char _comma
optional eol
return update
buildRules :: [(Int, Int)] -> Rules
buildRules =
fromList
. map (foldr construct (0, []))
. groupBy ((==) `on` fst)
. sortBy (comparing fst)
where
construct (a, b) (_, xs) = (a, b : xs)
sorted :: Rules -> Update -> Bool
sorted _ [] = True
sorted rules (x:xs)
| x `notMember` rules = sorted rules xs
| any (`elem` xs) . (!) rules $ x = False
| otherwise = sorted rules xs
checkSorted :: (Rules, [Update]) -> [Update]
checkSorted (rules, updates) = filter (sorted rules) updates
comparePages :: Rules -> Int -> Int -> Ordering
comparePages rules page1 page2
| page1 == page2 = EQ
| page2 `notMember` rules = GT
| page1 `elem` rules ! page2 = LT
| otherwise = GT
sortUnsorted :: (Rules, [Update]) -> [Update]
sortUnsorted (rules, updates) =
map (sortBy (comparePages rules)) . filter (not . sorted rules) $ updates
score :: Update -> Int
score update = (update !!) . flip div 2 . length $ update
part1 :: Bool -> ByteString -> String
part1 _ =
show
. sum
. map score
. checkSorted
. fromRight (empty, [])
. parse parseInput ""
part2 :: Bool -> ByteString -> String
part2 _ =
show
. sum
. map score
. sortUnsorted
. fromRight (empty, [])
. parse parseInput ""