Skip to content

Instantly share code, notes, and snippets.

@YuRen-tw
Last active May 28, 2018 07:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YuRen-tw/7d852147893b97d60b7eb49c55542be0 to your computer and use it in GitHub Desktop.
Save YuRen-tw/7d852147893b97d60b7eb49c55542be0 to your computer and use it in GitHub Desktop.
FLOLAC 2018 0-4: Caesar Cipher & Decipher
import Data.Char (ord, chr)
import Data.List
import Data.Function (on)
encode :: Int -> String -> String
encode n = map (shift n)
decode :: String -> (String, Int)
decode = aarrr mkPair (flip minimumBy [0..25] . compareOnDiff . count)
where aarrr f g x = f x $ g x
mkPair xs n = (encode n xs, mod (26-n) 26)
compareOnDiff c = compare `on` diff c
diff :: (Char -> Int) -> Int -> Int
diff c n = sum . change . sort' $ rank
where change = zipWith (\x y -> abs $ x - snd y) [0..25]
sort' = sortBy (flip compare `on` (count' . fst))
count' = c . shift (mod (26-n) 26)
count :: Eq a => [a] -> a -> Int
count = foldl count' (const 0)
where count' :: Eq a => (a -> Int) -> a -> (a -> Int)
count' f x y | x == y = f y + 1
| otherwise = f y
shift :: Int -> Char -> Char
shift n = chr . (\x -> mod (x-oA + n) 26 + oA) . ord
where oA = ord 'A'
-- https://en.wikipedia.org/wiki/Letter_frequency#Relative_frequencies_of_letters_in_the_English_language
-- ETAOINSHRDLCUMWFGYPBVKJXQZ
rank :: [(Char, Int)]
rank = [('A', 2), ('B', 19), ('C', 11), ('D', 9),
('E', 0), ('F', 15), ('G', 16), ('H', 7),
('I', 4), ('J', 22), ('K', 21), ('L', 10),
('M', 13), ('N', 5), ('O', 3), ('P', 18),
('Q', 24), ('R', 8), ('S', 6), ('T', 1),
('U', 12), ('V', 20), ('W', 14), ('X', 23),
('Y', 17), ('Z', 25)]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment