Skip to content

Commit

Permalink
changed 2 spaces to 4 spaces
Browse files Browse the repository at this point in the history
  • Loading branch information
Kelong Cong committed Nov 14, 2014
1 parent 76f22c4 commit 5703ce6
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 101 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ dist
cabal-dev
main
Main
Tests
*.o
*.hi
*.chi
Expand Down
116 changes: 62 additions & 54 deletions Enigma.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ type State = [Char] -- state of the enigma machine
data Direction = Fwd | Bwd deriving (Show, Eq)
data RotorSignalDir = SignalIn | SignalOut deriving (Show, Eq)
data Conf = Conf
{ getPlugboard :: String
, getRefl :: String
, getType :: [(String, Char)]
, getRing :: [Char]}
deriving (Show)
{ getPlugboard :: String
, getRefl :: String
, getType :: [(String, Char)]
, getRing :: [Char]}
deriving (Show)

-- enigma machine functions ---------------------------------------------------
-- this is for re-routing the signal to a different character
Expand All @@ -22,15 +22,15 @@ plugboard Fwd pbConf c = pbConf !! (charToInt c)
-- rotates a single rotor depending on the state and its configuration
rotateRotor :: Int -> Conf -> State -> State
rotateRotor 2 _ state =
(init state) ++ [cycleChar $ last state] -- move the last element
(init state) ++ [cycleChar $ last state] -- move the last element
rotateRotor x conf state
| cycleChar pawlLoc == rightLoc = part1 ++ (cycleChar currentLoc):part2
| otherwise = state
where
(part1,_:part2) = splitAt x state
pawlLoc = snd (getType conf !! (x+1))
rightLoc = state !! (x+1)
currentLoc = state !! x
| cycleChar pawlLoc == rightLoc = part1 ++ (cycleChar currentLoc):part2
| otherwise = state
where
(part1,_:part2) = splitAt x state
pawlLoc = snd (getType conf !! (x+1))
rightLoc = state !! (x+1)
currentLoc = state !! x

-- like the plugboard, also for re-routing the signal
reflector :: String -> Char -> Char
Expand All @@ -41,75 +41,83 @@ reflector refConf c = plugboard Bwd refConf c
-- rotor location and of course the input character respectively
rotor :: Direction -> (String,Char) -> Char -> Char -> Char -> Char
rotor dir rtype ring loc c = -- where rtype is rotor type
((rotorOffset SignalOut ring loc)
.(rotorWiring dir rtype)
.(rotorOffset SignalIn ring loc)) c
((rotorOffset SignalOut ring loc)
.(rotorWiring dir rtype)
.(rotorOffset SignalIn ring loc)) c

-- helper function for rotor: performs the offset
rotorOffset :: RotorSignalDir -> Char -> Char -> Char -> Char
rotorOffset dir ring loc c
| dir == SignalIn = intToChar $ rem26 $ ic + iloc - iring
| dir == SignalOut = intToChar $ rem26 $ ic - iloc + iring
| otherwise = error "Critical error in rotorOffset."
where
ic = charToInt c
iloc = charToInt loc
iring = charToInt ring
| dir == SignalIn = intToChar $ rem26 $ ic + iloc - iring
| dir == SignalOut = intToChar $ rem26 $ ic - iloc + iring
| otherwise = error "Critical error in rotorOffset."
where
ic = charToInt c
iloc = charToInt loc
iring = charToInt ring

-- helper function for rotor: uses the wiring table to reroute the signal
rotorWiring :: Direction -> (String,Char) -> Char -> Char
rotorWiring Fwd (wiring,_) c =
wiring !! charToInt c
wiring !! charToInt c
rotorWiring Bwd (wiring,_) c =
alphs !! getIndex c wiring
alphs !! getIndex c wiring

-- this function runs the enigma machine for a single character
-- this does not change the machine state
enigmaChar :: Conf -> State -> Char -> Char
enigmaChar conf state c =
( plugboard Bwd (getPlugboard conf)
. rotor Bwd ((getType conf) !! 2) ((getRing conf) !! 2) (state !! 2)
. rotor Bwd ((getType conf) !! 1) ((getRing conf) !! 1) (state !! 1)
. rotor Bwd ((getType conf) !! 0) ((getRing conf) !! 0) (state !! 0)
. reflector (getRefl conf)
. rotor Fwd ((getType conf) !! 0) ((getRing conf) !! 0) (state !! 0)
. rotor Fwd ((getType conf) !! 1) ((getRing conf) !! 1) (state !! 1)
. rotor Fwd ((getType conf) !! 2) ((getRing conf) !! 2) (state !! 2)
. plugboard Fwd (getPlugboard conf)
) c
enigmaChar conf state =
plugboard Bwd (getPlugboard conf)
. rotor Bwd ((getType conf) !! 2) ((getRing conf) !! 2) (state !! 2)
. rotor Bwd ((getType conf) !! 1) ((getRing conf) !! 1) (state !! 1)
. rotor Bwd ((getType conf) !! 0) ((getRing conf) !! 0) (state !! 0)
. reflector (getRefl conf)
. rotor Fwd ((getType conf) !! 0) ((getRing conf) !! 0) (state !! 0)
. rotor Fwd ((getType conf) !! 1) ((getRing conf) !! 1) (state !! 1)
. rotor Fwd ((getType conf) !! 2) ((getRing conf) !! 2) (state !! 2)
. plugboard Fwd (getPlugboard conf)

-- runs the enigma machine for a string
enigma :: Conf -> State -> String -> String
enigma _ _ [] = []
enigma conf state (x:rest) =
let newState =
((rotateRotor 0 conf)
.(rotateRotor 1 conf)
.(rotateRotor 2 conf)) state
in (enigmaChar conf newState x) : (enigma conf newState rest)
let newState =
((rotateRotor 0 conf)
.(rotateRotor 1 conf)
.(rotateRotor 2 conf)) state
in (enigmaChar conf newState x) : (enigma conf newState rest)


-- at the moment we're not including plugboard settings
intToSetting :: (Conf,State) -> [(String, Char)] -> [String] -> Int -> (Conf,State)
intToSetting (conf,state) allRTypes allReflectors n =
(Conf newPlugs newRefl newRType newRing, newState)
where
newPlugs = getPlugboard conf -- not considered at the moment
newRefl = nthElemSetting (nextReflector allReflectors) (m `quot` 18534946560) (getRefl conf)
newRType = nthElemSetting (nextRotorType allRTypes) (m `quot` 308915776) (getType conf)
newRing = nthElemSetting nextRingLoc (m `quot` 17576) (getRing conf)
newState = nthElemSetting nextRingLoc (m `rem` 17576) state
m = n `rem` 37069893120 -- (26^3 * 26^3 * 60 * 2) plugs not included
(Conf newPlugs newRefl newRType newRing, newState)
where
newPlugs = getPlugboard conf -- not considered at the moment
newRefl = nthElemSetting (nextReflector allReflectors) (m `quot` 18534946560) (getRefl conf)
newRType = nthElemSetting (nextRotorType allRTypes) (m `quot` 308915776) (getType conf)
newRing = nthElemSetting nextRingLoc (m `quot` 17576) (getRing conf)
newState = nthElemSetting nextRingLoc (m `rem` 17576) state
m = n `rem` 37069893120 -- (26^3 * 26^3 * 60 * 2) plugs not included

intToSettingDefault :: Int -> (Conf, State)
intToSettingDefault =
intToSetting (Conf plugs refB [rtypeI,rtypeII,rtypeIII] "AAA", "AAA")
[rtypeI, rtypeII, rtypeIII, rtypeIV, rtypeV] [refB, refC]
intToSetting (Conf plugs refB [rtypeI,rtypeII,rtypeIII] "AAA", "AAA")
[rtypeI, rtypeII, rtypeIII, rtypeIV, rtypeV] [refB, refC]

-- some default configurations
plugs = ['A'..'Z'] -- plug locations, only wires in real enigma
refB = "YRUHQSLDPXNGOKMIEBFZCWVJAT" -- M3 B reflector
refC = "FVPJIAOYEDRZXWGCTKUQSBNMHL" -- M3 C reflector
plugs :: String
refB :: String
refC :: String
rtypeI :: (String, Char)
rtypeII :: (String, Char)
rtypeIII :: (String, Char)
rtypeIV :: (String, Char)
rtypeV :: (String, Char)

plugs = ['A'..'Z'] -- plug locations, only wires in real enigma
refB = "YRUHQSLDPXNGOKMIEBFZCWVJAT" -- M3 B reflector
refC = "FVPJIAOYEDRZXWGCTKUQSBNMHL" -- M3 C reflector
rtypeI = ("EKMFLGDQVZNTOWYHXUSPAIBRCJ", 'Q') -- rotor type I
rtypeII = ("AJDKSIRUXBLHWTMCQGZNPYFVOE", 'E') -- rotor type II
rtypeIII = ("BDFHJLCPRTXVZNYEIWGAKMUSQO", 'V') -- rotor type III
Expand Down
42 changes: 21 additions & 21 deletions Helper.hs
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@

module Helper where

import Data.Char (ord, chr, isUpper)
import Data.Char (ord, chr, isAsciiUpper)
import Data.Maybe (fromJust)
import Data.List (elemIndex, nub, delete)

-- helper functions -----------------------------------------------------------
alphs :: [Char]
alphs :: String
alphs = ['A'..'Z']

rem26 :: Int -> Int
rem26 x = rem (x+52) 26

charToInt :: Char -> Int
charToInt c
| c >= 'A' && c <= 'Z' = (ord c) - 65
| otherwise = error "Not a capital alphabet in charToInt."
| isAsciiUpper c = ord c - 65
| otherwise = error "Not a capital alphabet in charToInt."

intToChar :: Int -> Char
intToChar x
| x >= 0 && x <= 25 = chr $ x + 65
| otherwise = error "Argument is not between 0 and 25 in intToChar."
| x >= 0 && x <= 25 = chr $ x + 65
| otherwise = error "Argument is not between 0 and 25 in intToChar."

getIndex :: Eq a => a -> [a] -> Int
getIndex x xs = fromJust $ elemIndex x xs

cycleChar :: Char -> Char
cycleChar c
| c == 'Z' = 'A'
| c >= 'A' && c <= 'Z' = succ c
| otherwise = error "Argument is not between 'A' and 'Z' in cycleChar."
| c == 'Z' = 'A'
| isAsciiUpper c = succ c
| otherwise = error "Argument is not between 'A' and 'Z' in cycleChar."

cycleList :: Eq a => [a] -> a -> a
cycleList [x] _ = x
cycleList xs a
| a == last xs = head xs
| otherwise = xs !! (1 + getIndex a xs)
| a == last xs = head xs
| otherwise = xs !! (1 + getIndex a xs)

-- perform k-permutation
kperm :: Eq a => Int -> [a] -> [[a]]
Expand All @@ -47,27 +47,27 @@ kperm k xs = [x:ys | x <- xs, ys <- kperm (k-1) (delete x xs)]
nthElemSetting :: (a -> a) -> Int -> a -> a
nthElemSetting _ 0 start = start
nthElemSetting nextfn n start =
nthElemSetting nextfn (n-1) (nextfn start)
nthElemSetting nextfn (n-1) (nextfn start)

-- same as cycleList but for string
-- 2 possibilities
nextReflector :: [String] -> String -> String
nextReflector rs r = cycleList rs r
nextReflector = cycleList

-- get the next location for the ring or the rotor location setting
-- 26*26*26 17576 possibilities
nextRingLoc :: String -> String
nextRingLoc [] = error "empty string in nextRingLoc"
nextRingLoc [a] = [cycleChar a]
nextRingLoc (x:xs)
| all (== 'Z') xs = cycleChar x : nextRingLoc xs
| otherwise = x : nextRingLoc xs
| all (== 'Z') xs = cycleChar x : nextRingLoc xs
| otherwise = x : nextRingLoc xs

-- returns next permutation element for k = 3
-- 5!/3! 60 possibilities
nextRotorType :: Eq a => [a] -> [a] -> [a]
nextRotorType allSettings setting =
cycleList (kperm 3 allSettings) setting -- currently hardcoded to be 3
nextRotorType allSettings =
cycleList (kperm 3 allSettings) -- currently hardcoded to be 3

-- this is used for optional parameter, same as flip fromMaybe
-- (//) :: Maybe a -> a -> a
Expand All @@ -76,12 +76,12 @@ nextRotorType allSettings setting =

-- verification functions -----------------------------------------------------
verifyInput :: String -> Bool
verifyInput = all isUpper
verifyInput = all isAsciiUpper

verifyConfStr :: String -> Bool
verifyConfStr xs =
verifyInput xs
&& length xs == 26
&& length (nub xs) == 26
verifyInput xs
&& length xs == 26
&& length (nub xs) == 26


5 changes: 3 additions & 2 deletions Main.hs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@

import Enigma

confs :: (Conf, State)
confs = intToSettingDefault 0

main :: IO ()
main = do
msg <- getLine
putStrLn (enigma (fst confs) (snd confs) msg)
msg <- getLine
putStrLn $ enigma (fst confs) (snd confs) msg


5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
WFLAGS=-Wall

all:
ghc -Wall Main.hs
ghc --make $(WFLAGS) Main.hs
ghc Tests.hs
clean:
rm -rf *.o *.hi Main
45 changes: 22 additions & 23 deletions Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,57 +6,56 @@ import Enigma
aaaConf = Conf plugs refB [rtypeI,rtypeII,rtypeIII] "AAA"
aaaState = "AAA"

-- |encoding those letter will cause two rotors to rotate
aaaTest3A =
enigma aaaConf "AAT" "AAA" == "BMU"
-- encoding those letter will cause two rotors to rotate
aaaTest3A = enigma aaaConf "AAT" "AAA" == "BMU"

aaaTest48A =
(enigma aaaConf aaaState $ replicate 48 'A')
== "BDZGOWCXLTKSBTMCDLPBMUQOFXYHCXTGYJFLINHNXSHIUNTH"
enigma aaaConf aaaState (replicate 48 'A')
== "BDZGOWCXLTKSBTMCDLPBMUQOFXYHCXTGYJFLINHNXSHIUNTH"

aaaTest48ADecode =
enigma aaaConf aaaState "BDZGOWCXLTKSBTMCDLPBMUQOFXYHCXTGYJFLINHNXSHIUNTH"
== replicate 48 'A'
enigma aaaConf aaaState "BDZGOWCXLTKSBTMCDLPBMUQOFXYHCXTGYJFLINHNXSHIUNTH"
== replicate 48 'A'


-- rotor test -----------------------------------------------------------------
rotorTest =
((rotateRotor 0 aaaConf) . (rotateRotor 1 aaaConf) . (rotateRotor 2 aaaConf)) "AAU"
== "AAV"
((rotateRotor 0 aaaConf) . (rotateRotor 1 aaaConf) . (rotateRotor 2 aaaConf)) "AAU"
== "AAV"


-- detailed tests: encode A at rotor pos AAV using default settings -----------
rotor2FwdTest =
(rotor Fwd ((getType aaaConf) !! 2) ((getRing aaaConf) !! 2) 'V' 'A')
== 'R'
(rotor Fwd ((getType aaaConf) !! 2) ((getRing aaaConf) !! 2) 'V' 'A')
== 'R'

-- carried forward from rotor2FwdTest
rotor1FwdTest =
(rotor Fwd ((getType aaaConf) !! 1) ((getRing aaaConf) !! 1) 'A' 'R')
== 'G'
(rotor Fwd ((getType aaaConf) !! 1) ((getRing aaaConf) !! 1) 'A' 'R')
== 'G'

-- carried forward from rotor1FwdTest
rotor0FwdTest =
(rotor Fwd ((getType aaaConf) !! 0) ((getRing aaaConf) !! 0) 'A' 'G')
== 'D'
(rotor Fwd ((getType aaaConf) !! 0) ((getRing aaaConf) !! 0) 'A' 'G')
== 'D'

-- reflector
reflectorTest = reflector refB 'D' == 'H'

-- backwards now..
rotor0BwdTest =
(rotor Bwd ((getType aaaConf) !! 0) ((getRing aaaConf) !! 0) 'A' 'H')
== 'P'
(rotor Bwd ((getType aaaConf) !! 0) ((getRing aaaConf) !! 0) 'A' 'H')
== 'P'

rotor1BwdTest =
(rotor Bwd ((getType aaaConf) !! 1) ((getRing aaaConf) !! 1) 'A' 'P')
==
'U'
(rotor Bwd ((getType aaaConf) !! 1) ((getRing aaaConf) !! 1) 'A' 'P')
==
'U'

rotor2BwdTest =
(rotor Bwd ((getType aaaConf) !! 2) ((getRing aaaConf) !! 2) 'V' 'U')
==
'M'
(rotor Bwd ((getType aaaConf) !! 2) ((getRing aaaConf) !! 2) 'V' 'U')
==
'M'

main =
print $
Expand Down

0 comments on commit 5703ce6

Please sign in to comment.