module Day12 where import Data.HashSet (HashSet, member, insert, fromList) import Data.Map ( Map, fromList, unionWith, empty, (!) ) import Data.List.Split (splitOn) import qualified Data.Char type Cave = String type Path = (Cave,Cave) type System = Map Cave [Cave] readPath :: String -> Path readPath s = (from,to) where [from,to] = splitOn "-" s addPath :: Path -> System -> System addPath (from,to) = unionWith (++) (Data.Map.fromList [(from,[to]), (to,[from])]) isUpper :: Cave -> Bool isUpper = Data.Char.isUpper . head pathFinder :: System -> Cave -> HashSet Cave -> Int pathFinder sys "end" _ = 1 pathFinder sys x visited = sum $ map (\next -> pathFinder sys next (next `insert` visited)) elig where elig = filter (\cave -> isUpper cave || not (cave `member` visited)) (sys ! x) pathFinder2 :: System -> Cave -> HashSet Cave -> Int pathFinder2 sys "end" _ = 1 pathFinder2 sys x visited = sum $ map (\next -> f next sys next (next `insert` visited)) elig where f cave = if isUpper cave || not (cave `member` visited) then pathFinder2 else pathFinder elig = filter (/= "start") (sys ! x) main :: IO () main = do input <- map readPath . lines <$> getContents let system = foldr addPath Data.Map.empty input putStrLn "part 1: " print $ pathFinder system "start" (Data.HashSet.fromList ["start"]) putStrLn "part 2: " print $ pathFinder2 system "start" (Data.HashSet.fromList ["start"])