Advent of Code solutions
1import Text.Parsec
2import Data.Set qualified as Set
3import Data.Map qualified as Map
4import Data.Map ((!))
5import Data.Char
6
7parseEdge = do
8 l <- many letter
9 char '-'
10 r <- many letter
11 return $ Map.fromList [(r, [l]), (l, [r])]
12
13parseGraph = Map.unionsWith (++) <$> parseEdge `endBy` newline
14
15allPaths graph = paths False Set.empty "start"
16 where
17 paths dup visited here
18 | here == "end" = 1
19 | all isLower here && Set.member here visited && here == "start" = 0
20 | all isLower here && Set.member here visited && dup = 0
21 | all isLower here && Set.member here visited = continue True inserted here
22 | all isLower here = continue dup inserted here
23 | otherwise = continue dup visited here
24 where
25 inserted = Set.insert here visited
26 continue dup visited here = sum $ do
27 next <- graph ! here
28 return $ paths dup visited next
29
30answer contents = allPaths graph
31 where
32 Right graph = parse parseGraph "" contents
33
34main = getContents >>= print . answer