Skip to content

Instantly share code, notes, and snippets.

@qoelet
Created August 3, 2013 07:43
Show Gist options
  • Save qoelet/6145618 to your computer and use it in GitHub Desktop.
Save qoelet/6145618 to your computer and use it in GitHub Desktop.
Full code of Caesar's cipher exercise from Hutton's book
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