import Control.Monad import Data.Char import Data.List import Data.Maybe splitOn :: Eq a => a -> [a] -> [[a]] splitOn c xs = case break (== c) xs of (pre, []) -> [pre] (pre, _ : post) -> pre : splitOn c post strip :: String -> String strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse swap :: Int -> Int -> [a] -> [a] swap i j (hd:tl) = case (i, j) of (0, _) -> uncurry (:) (go (j-1) hd tl) (_, 0) -> uncurry (:) (go (i-1) hd tl) (_, _) -> hd : swap (i-1) (j-1) tl where go 0 v (hd:tl) = (hd, v : tl) go k v (hd:tl) = fmap (hd :) (go (k-1) v tl) data Ins = Spin Int | Exch Int Int | Part Int Int deriving Show newtype State = State [Int] instance Show State where show (State ar) = map (chr . (+ ord 'a')) ar parse :: String -> Ins parse ('s' : s) = Spin (read s) parse ('x' : s) = let [a, b] = splitOn '/' s in Exch (read a) (read b) parse ['p', a, '/', b] = Part (ord a - ord 'a') (ord b - ord 'a') exec :: State -> Ins -> State exec (State ar) (Spin n) = State $ take 16 (drop (16 - n) (cycle ar)) exec (State ar) (Exch i j) = State $ swap i j ar exec (State ar) (Part a b) = let i = fromMaybe (-1) (findIndex (== a) ar) j = fromMaybe (-1) (findIndex (== b) ar) in State $ swap i j ar main :: IO () main = do input <- liftM (map parse . splitOn ',' . strip) (readFile "16.in") print (foldl exec (State [0..15]) input)