-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay5.hs
77 lines (63 loc) · 2.92 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
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Attoparsec.Text as At
import qualified Data.Attoparsec.Combinator as Atc
import qualified Data.Text as T
import qualified Data.IntSet as IS
import Control.Applicative
import Control.Monad
import Data.Functor
import Data.Bifunctor (bimap)
import Data.Maybe (isJust, fromJust, catMaybes)
import Data.Ix (inRange)
import Data.List.Split (chunksOf)
import Data.List (sort)
import AocLib
type Seeds = [Int]
data Mapping = Mapping { dStart :: Int, dEnd :: Int, sStart :: Int, sEnd :: Int } deriving Show
mappingFn :: [Mapping] -> Int -> Int
mappingFn ms key = if null candidates then key else offset $ head candidates
where keyInRange (Mapping ds de ss se) = ss <= key && key < se
candidates = filter keyInRange ms
offset (Mapping ds de ss se) = key - ss + ds
parser :: At.Parser (Seeds, [[Mapping]])
parser = do
let parseMapLine = do
ds <- At.decimal <* At.space
ss <- At.decimal <* At.space
l <- pred <$> At.decimal
return (Mapping ds (ds + l) ss (ss + l))
identifier = At.many1 (At.letter <|> At.char '-')
parseMap = do
identifier <* At.string " map:" <* At.endOfLine
At.many1 (parseMapLine <* At.endOfLine)
seeds <- At.string "seeds: " *> At.sepBy1 At.decimal At.space <* At.many' At.endOfLine
mappings <- At.sepBy1 parseMap At.endOfLine
return (seeds, mappings)
type Range = (Int, Int)
splitRange :: Range -> Range -> (Maybe Range, [Range])
splitRange (a, m) (b, n) -- a is reference to split
| inRange (a, m) b || inRange (b, n) a = (Just (max a b, min m n), restOfChunks)
| otherwise = (Nothing, [(a, m)])
where validRange (l, r) = l <= r && l >= a && r <= m
restOfChunks = filter validRange [(min a b, max a b - 1), (min m n + 1, max m n)]
breakMappings :: [Mapping] -> [Range] -> [Range]
breakMappings ms as = let (ov, no) = foldr breakMapping ([], as) ms
in ov ++ no
-- (overlapping range, non-overlapping range)
breakMapping :: Mapping -> ([Range], [Range]) -> ([Range], [Range])
breakMapping (Mapping dS _ sS sE) (ov, no) = let match = map (`splitRange` (sS, sE)) no
(ov1, no1) = bimap catMaybes concat $ unzip match
mapFn a = a - sS + dS
mapRange = bimap mapFn mapFn
mapOv = map mapRange ov1
in (ov ++ mapOv, no1)
main :: IO ()
main = do
(seeds, mappings) <- parseInput parser
let lookupFn = foldl1 (flip (.)) $ map mappingFn mappings
solve1 = minimum $ map lookupFn seeds
print solve1
let seedranges = map (\[a, l] -> (a, a + l - 1)) $ chunksOf 2 seeds
ranges = foldl (flip breakMappings) seedranges mappings
solve2 = fst $ minimum ranges
print solve2