import Data.List (elemIndex) chao :: Eq a => [a] -> [a] -> Bool -> [a] -> [a] chao _ _ _ [] = [] chao l r plain (x : xs) = maybe [] go (elemIndex x src) where (src, dst) | plain = (l, r) | otherwise = (r, l) go n = dst !! n : chao (shifted 1 14 (rotated n l)) ((shifted 2 14 . shifted 0 26) (rotated n r)) plain xs rotated :: Int -> [a] -> [a] rotated n = take . length <*> drop n . cycle shifted :: Int -> Int -> [a] -> [a] shifted src dst s = concat [x, rotated 1 y, b] where (a, b) = splitAt dst s (x, y) = splitAt src a encode, decode :: Bool encode = False decode = True main :: IO () main = do let chaoWheels = chao "HXUCZVAMDSLKPEFJRIGTWOBNYQ" "PTLNBQDEOYSFAVZKGJRIHWXUMC" plainText = "WELLDONEISBETTERTHANWELLSAID" cipherText = chaoWheels encode plainText mapM_ print [ plainText, cipherText, chaoWheels decode cipherText ]