{-# 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
