Programing in Haskell Chapter5 / Cracking the cipher
今日は暗号解読のプログラミングを書き写してみました。
Programing in Haskell(http://www.amazon.co.jp/dp/0521692695) P.38-46
import Data.Char as C -- xと等しい要素をもつリストxsの位置情報を返す positions :: Eq a => a -> [a] -> [Int] positions x xs = [ i | (y, i) <- zip xs [0..n], x == y] where n = length xs - 1 -- 小文字のaを基準にして、aとの相対位置を返す -- a -> 0, b -> 1 .... let2int :: Char -> Int let2int c = C.ord c - C.ord 'a' -- 1~25に応じて、数字を小文字アルファベットに返す -- 0 -> a, 1 -> b ... int2let :: Int -> Char int2let n = C.chr (C.ord 'a' + n) -- a-zなら、(mod n 26)個分シフトしたアルファベットを返す shift :: Int -> Char -> Char shift n c | C.isLower c = int2let ((let2int c + n) `mod` 26) | otherwise = c encode :: Int -> String -> String encode n xs = [ shift n x | x <- xs ] 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] percent :: Int -> Int -> Float percent n m = (fromIntegral n / fromIntegral m ) * 100 count x xs = length [ i | i <- xs, x == i ] lowers xs = length [ c | c <- xs, 'a' <= c && c <= 'z' ] freqs :: String -> [Float] freqs xs = [percent (count x xs) n | x <- ['a' .. 'z' ] ] where n = lowers xs -- 母集団の要素eとそれ以外の集団oが -- どれくらい離れているかを計算する 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) -- encodeされたxsを(-factor)分encodeする -> decode 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
すごい!すごい!すごい!
*Main> crack "kdvnhoo lv ixq" "haskell is fun"
明日はバシッと練習問題!