Created
August 3, 2013 07:43
-
-
Save qoelet/6145618 to your computer and use it in GitHub Desktop.
Full code of Caesar's cipher exercise from Hutton's book
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Data.Char | |
-- frequencies based on large number of text | |
table :: [Float] | |
table = [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] | |
-- earlier functions in the chapter required here | |
lowers :: String -> Int | |
lowers xs = length [ x | x <- xs, isLower x] | |
count :: Char -> String -> Int | |
count x xs = length [x' | x' <- xs, x == x'] | |
positions :: Eq a => a -> [a] -> [Int] | |
positions x xs = [i | (x',i) <- zip xs [0..n], x == x'] | |
where n = length xs - 1 | |
-- define a function that calculates the % of one integer with respect to another, returning result as a floating-point number | |
percent :: Int -> Int -> Float | |
percent n m = 100 * (a / b) | |
where a = fromIntegral n :: Float | |
b = fromIntegral m :: Float | |
-- define a function that returns a frequency table for any string | |
freqs :: String -> [Float] | |
freqs xs = [percent (count x xs) n | x <- ['a'..'z']] | |
where n = lowers xs | |
-- the smaller the value of the chi-square stat, the better the match between 2 frequency lists | |
chisqr :: [Float] -> [Float] -> Float | |
chisqr os es = sum [((o - e) ^ 2) / e | (o, e) <- zip os es] | |
-- define a function that rotates the elements of a list n places to the left, wrapping around the start of the list, | |
-- and assuming that n is between zero and the length of the list | |
rotate :: Int -> [a] -> [a] | |
rotate n xs = drop n xs ++ take n xs | |
-- encode function & subfunctions | |
let2int :: Char -> Int | |
let2int c = ord c - ord 'a' | |
int2let :: Int -> Char | |
int2let n = chr (ord 'a' + n) | |
shift :: Int -> Char -> Char | |
shift n c | isLower c = int2let((let2int c + n) `mod` 26) | |
| otherwise = c | |
encode :: Int -> String -> String | |
encode n xs = [shift n x | x <- xs] | |
-- crack function | |
crack :: String -> String | |
crack xs = encode (-factor) xs | |
where | |
factor = head (positions (minimum chitab) chitab) | |
chitab = [chisqr (rotate n table') table | n <- [0..25]] | |
table' = freqs xs | |
-- e.g. encode 3 'this is a message' | |
-- e.g. crack "wklv lv d phvvdjh" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment