module S03 (
rotate,
int2let, let2int, shift, encode,
freqs,
chisqr,
crack
) where
import Data.Char
tableEn :: [Float]
tableEn = [8.2,1.5,2.8,4.3,12.7,2.2,2.0,6.1,7.0,
0.2, 0.8,4.0,2.4,6.7,7.5,1.9,0.1,6.0,
6.3,9.1,2.8,1.0,2.4,0.2,2.0,0.1]
int2let :: Int -> Char
int2let i = chr (ord 'a' + i)
let2int :: Char -> Int
let2int c = ord c ord 'a'
shift :: Int -> Char -> Char
shift n c | isLower c = int2let ((let2int c + n) `mod` 26)
| otherwise = c
encode :: Int -> String -> String
encode k = map (shift k)
ratio :: Int -> Int -> Float
ratio m n = (fromIntegral m * 100) / fromIntegral n
count :: Char -> String -> Int
count x xs = length [x' | x' <- xs, x == x']
freqs :: String -> [Float]
freqs xs = [count x xs `ratio` n | x <- ['a'..'z']]
where n = length (filter isLower xs)
chisqr :: [Float] -> [Float] -> Float
chisqr os es = sum [((o e)^2)/e | (o,e) <- zip os es]
rotate :: Int -> [a] -> [a]
rotate n xs = drop n xs ++ take n xs
crack :: String -> String
crack xs = encode (key) xs
where
key = head [i | (chi,i) <- zip chitab [0..25], chi == minimum chitab]
chitab = [chisqr (rotate n table') tableEn | n <- [0..25]]
table' = freqs xs