-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDay06.hs
104 lines (86 loc) · 2.01 KB
/
Day06.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
module Main where
import Utilities
import Parser
import Control.Applicative
import Data.Map (Map, (!))
import qualified Data.Map as Map
-- Input processing
type Input = Tree Body
-- tree represented as a mapping of each node to its parent
type Tree a = Map a a
type Body = String
parse :: String -> Input
parse = Map.fromList .map (runParser orbit) . lines
where
orbit = flip (,) <$> body <* char ')' <*> body
body = some (digit <|> letter)
-- Part One
-- depth of each node
depths :: Ord a => Tree a -> Map a Int
depths t = depth_map
where
depth_map = fmap depth t
depth a = maybe 1 (1+) (Map.lookup a depth_map)
solve1 :: Input -> Int
solve1 = sum . depths
testInput :: String
testInput = "\
\COM)B\n\
\B)C\n\
\C)D\n\
\D)E\n\
\E)F\n\
\B)G\n\
\G)H\n\
\D)I\n\
\E)J\n\
\J)K\n\
\K)L\n\
\"
tests1 :: [(String, Int)]
tests1 = [(testInput, 42)]
-- Part Two
-- path from each node to the root (not including the start node or the root)
paths :: Ord a => Tree a -> Map a [a]
paths t = path_map
where
path_map = fmap path t
path a = maybe [] (a:) (Map.lookup a path_map)
-- sum of the lengths of the different parts of paths from two nodes
transfers :: Ord a => a -> a -> Map a [a] -> Int
transfers a b path_map =
length pa + length pb - 2*length (commonPrefix pa pb)
where
pa = reverse (path_map!a)
pb = reverse (path_map!b)
-- longest common prefix of two lists
commonPrefix :: Eq a => [a] -> [a] -> [a]
commonPrefix xs ys = map fst $ takeWhile (uncurry (==)) $ zip xs ys
solve2 :: Input -> Int
solve2 = transfers "YOU" "SAN" . paths
testInput2 :: String
testInput2 = "\
\COM)B\n\
\B)C\n\
\C)D\n\
\D)E\n\
\E)F\n\
\B)G\n\
\G)H\n\
\D)I\n\
\E)J\n\
\J)K\n\
\K)L\n\
\K)YOU\n\
\I)SAN\n\
\"
tests2 :: [(String, Int)]
tests2 = [(testInput2, 4)]
main :: IO ()
main = do
s <- readFile "input/06.txt"
let input = parse s
putStr (unlines (failures "solve1" (solve1 . parse) tests1))
print (solve1 input)
putStr (unlines (failures "solve2" (solve2 . parse) tests2))
print (solve2 input)