DEV Community

Discussion on: Daily Challenge #113 - Iterative Rotation Cipher

Collapse
 
craigmc08 profile image
Craig McIlwrath

Here's my solution in Haskell:

import Data.Char (isDigit)

applyN :: Int -> (a -> a) -> a -> a
applyN n f = foldr (.) id (replicate n f)

shift :: Int -> [a] -> [a]
shift _ [] = []
shift 0 xs = xs
shift n xs = shift (n - 1) $ last xs : init xs

unshift :: Int -> [a] -> [a]
unshift _ [] = []
unshift 0 xs = xs
unshift n (x:xs) = unshift (n - 1) $ xs ++ [x]

saveSpaces :: String -> [Int]
saveSpaces [] = []
saveSpaces (' ':cs) = 0 : map (+1) (saveSpaces cs)
saveSpaces (_:cs) = map (+1) (saveSpaces cs)

restoreSpaces :: [Int] -> String -> String
restoreSpaces [] cs = cs
restoreSpaces (0:ns) cs = ' ' : restoreSpaces (map (+(-1)) ns) cs
restoreSpaces ns (c:cs) = c : restoreSpaces (map (+(-1)) ns) cs

splitAfterNumber :: String -> (Int, String)
splitAfterNumber cs = let (dgts, str) = span isDigit cs
                      in (read dgts :: Int, tail str)

encodeStep :: Int -> String -> String
encodeStep n cs = let spaces = saveSpaces cs
                  in  unwords $
                      map (shift n) $
                      words $
                      restoreSpaces spaces $
                      shift n $
                      filter (/=' ') cs

encode :: Int -> String -> String
encode n = ((show n ++ " ")++) . applyN n (encodeStep n)

decodeStep :: Int -> String -> String
decodeStep n cs = let spaces = saveSpaces cs
                  in  restoreSpaces spaces $
                      unshift n $
                      filter (/=' ') $
                      unwords $
                      map (unshift n) $
                      words cs

decode :: String -> String
decode cs = let (n, str) = splitAfterNumber cs
            in applyN n (decodeStep n) str

There's no validation of the input to decode. Also, I'm not sure if the second test provided for decode is correct. I'm not getting any English words out of it, but my decode function hasn't failed besides that test.