-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday-3.hs
107 lines (95 loc) · 2.55 KB
/
day-3.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
module Main where
import AoC
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.List (groupBy, foldl', sort)
import Data.Containers.ListUtils (nubOrd)
import Data.Char (isDigit)
import Control.Monad.Trans.Writer.CPS (runWriter, tell, censor)
import Algorithm.Search (dfsM, pruning)
import Data.Maybe (maybeToList, fromJust)
type M = Map P Char
type C = (M, Int, Int)
solve :: [String] -> Int -> Int
solve inp =
\case
1 -> part1
2 -> part2
where
c@(m, rmx, cmx) = parse inp
rs = roots m
digs = sort $ nubOrd $ foldl' f [] rs
where
f ds p = ds ++ dfsRoot c p
nums :: [Int]
nums
= digs
|> groupAdj
.> numify
numify = map (map ((`M.lookup` m) .> fromJust) .> read)
part1 = sum nums
rs' = filter ((`M.lookup` m) .> fromJust .> (== '*'))
digs' = map f' rs
where
f' r = (r, dfsRoot c r |> nubOrd .> sort .> groupAdj)
digs'' = filter (\(r,ns) -> length ns == 2) digs'
part2 = map (snd .> numify .> product) digs'' |> sum
groupAdj (p:ps) = go [[p]] ps
where
go (xs:xss) [] = reverse xs : xss
go (xs@(q@(P rp cp) : qs):xss) (p@(P r c):ps)
| r == rp && cp + 1 == c
= go ((p:xs):xss) ps
| otherwise
= go ([p]:reverse xs:xss) ps
dfsRoot :: C -> P -> [P]
dfsRoot c@(m,rmx,cmx) r = res
where
res = nubOrd $ concatMap myDfs (init r)
myDfs :: P -> [P]
myDfs init =
let (_, res) = runWriter $ dfsM (next c) (const False .> pure) init
in init : res
init q@(P r c)
= [ p
| dr <- [-1..1]
, dc <- [-1..1]
, let r' = r+dr
, let c' = c+dc
, let p = P r' c'
, p /= q
, c <- maybeToList $ p `M.lookup` m
, isDigit c
] |> filter (outofbound rmx cmx .> not)
next (m,rmx,cmx) = eps
`pruning` outofbound rmx cmx
`pruning`
((`M.lookup` m)
.> \case
Nothing -> True
Just c -> not $ isDigit c
)
.> (\ps -> censor (ps++) (pure ps))
where
eps (P r c) = [P r (c-1), P r (c+1)]
outofbound rmx cmx (P r c)
= not
$ 0 <= r && r < rmx
&& 0 <= c && c < cmx
roots :: M -> [P]
roots = M.foldrWithKey f []
where
f p c rs
| not $ isDigit c = p : rs
| otherwise = rs
parse :: [String] -> C
parse inp = (M.fromList psAll, length inp, length $ head inp)
where
psAll = foldl' fr [] (zip [0..] inp)
fr ps (r, line) = foldl' fc ps (zip [0..] line)
where
fc ps (c, x)
| x == '.' = ps
| otherwise = (P r c, x) : ps
main :: IO ()
main = defaultMain solve