{-# LANGUAGE LambdaCase #-} import Control.Arrow import Data.Char import Data.List.Split import qualified Data.Map as M type LR a = (a, a) -> a type Tunnels = M.Map String (String, String) main :: IO () main = interact $ show . day08 . parse . lines parse :: [String] -> ([LR String], Tunnels) parse = cycle . map (\case 'L' -> fst 'R' -> snd _ -> error "Malformed directions input") . head &&& M.fromList . map parseLine . tail . tail parseLine :: String -> (String, (String, String)) parseLine s = (a, (b, c)) where [a, b, c] = wordsBy (not . isAlphaNum) s day08 :: ([LR String], Tunnels) -> (Int, Int) day08 (lrs, m) = day08a lrs m *** day08b lrs m $ ("AAA", starts) where starts = filter ((== 'A') . last) (M.keys m) day08a :: [LR String] -> Tunnels -> String -> Int day08a _ _ [_, _, 'Z'] = 0 day08a (lr:lrs) m pos = 1 + day08a lrs m (lr (m M.! pos)) day08b :: [LR String] -> Tunnels -> [String] -> Int day08b lrs m starts = foldr1 lcm $ map (day08a lrs m) starts