Today’s Programming Praxis problem is another cipher, specifically Bifid’s cipher. Let’s get started, shall we?
import Data.Char import Data.List import Data.List.HT hiding (unzip) import Data.Map ((!), fromList)
There’s no J in the Bifid alphabet.
alphabet :: String alphabet = delete 'J' ['A'..'Z']
Next we need some functions to get the index from a character and vice versa. The second line in fromIndex is only to get rid of a compiler warning; you can leave it out if you want to.
indices :: [(Int, Int)] indices = zip (concatMap (replicate 5) [1..5]) (cycle [1..5]) toIndex :: Char -> (Int, Int) toIndex c = fromList (zip alphabet indices) ! c fromIndex :: [Int] -> Char fromIndex [x, y] = fromList (zip indices alphabet) ! (x, y) fromIndex _ = undefined
Next, we need a way to prepare the strings for the algorithm.
prepare :: String -> String prepare = filter (`elem` alphabet) . replace "J" "I" . map toUpper
The basic structure of encode and decode is the same, only the way of getting the intermediate data in the right order differs.
encode :: String -> String encode = map fromIndex . sliceVertical 2 . uncurry (++) . unzip . map toIndex . prepare decode :: String -> String decode xs = map fromIndex . sliceHorizontal (length xs) . concatMap ((\(x, y) -> [x, y]) . toIndex) $ prepare xs
And, as usual, some tests to see if everything’s working properly:
main :: IO () main = do print $ encode "BONSAICODE" print . decode $ encode "BONSAICODE"
Looks like it is. Another one down.