-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay5.hs
57 lines (50 loc) · 1.82 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
module Javran.AdventOfCode.Y2023.Day5 () where
import Control.Applicative
import Control.Monad
import qualified Data.IntMap.Strict as IM
import Data.List
import Data.List.Split hiding (sepBy)
import Javran.AdventOfCode.Prelude
import Text.ParserCombinators.ReadP hiding (count, get, many)
data Day5 deriving (Generic)
type AMapEntry = (Int, Int, Int)
type AlmanacMap = [AMapEntry]
almanacP :: ReadP ([Int], [AlmanacMap])
almanacP = do
let nl = charP '\n'
sp = charP ' '
seeds <- strP "seeds:" *> many (sp *> decimal1P) <* nl
let ws = words "seed soil fertilizer water light temperature humidity location"
entryP = (,,) <$> (decimal1P <* sp) <*> (decimal1P <* sp) <*> (decimal1P <* nl)
rs <- forM (zip ws (tail ws)) \(l, r) -> do
nl
strP (l <> "-to-" <> r <> " map:") <* nl
many entryP
pure (seeds, rs)
mkMapper :: AlmanacMap -> Int -> Int
mkMapper xs = auxLookup
where
-- key: src, value: (dst, range)
m :: IM.IntMap (Int, Int)
m = IM.fromList do
(dst, src, rng) <- xs
pure (src, (dst, rng))
-- rely on split and maxView on left result to do our work
auxLookup i
| Just (dst, _) <- cur = dst
| Just ((src, (dst, rng)), _) <- IM.maxViewWithKey lm
, i < src + rng =
dst + (i - src)
| otherwise = i
where
(lm, cur, _) = IM.splitLookup i m
-- TODO: may want to go back and figure out how to do this faster.
-- TODO: I feel IntMap might have added too much overhead to our liking. need to try a linear version.
instance Solution Day5 where
solutionRun _ SolutionContext {getInputS, answerShow} = do
(seeds, maps) <- consumeOrDie almanacP <$> getInputS
let ff = foldl' (\r m -> mkMapper m . r) id maps
answerShow (minimum $ fmap ff seeds)
answerShow $ minimum do
[l, rng] <- chunksOf 2 seeds
fmap ff [l .. l + rng - 1]