--------------------
-- Sample implementations of Rot13
-- Fritz Ruehr * CS 154 * Fall 2012
--------------------

module Rots where

import Char


rot13 = map rotc1

sample = "This is a message; it is a test, just a test."


--------------------
-- characterwise functions in several different styles

rotc0 c =      if isUpper c then (if c <= 'M' then chr (ord c + 13)
                                              else chr (ord c - 13))
          else if isLower c then (if c <= 'm' then chr (ord c + 13)
                                              else chr (ord c - 13))
          else c

rotc1 c =      if 'A' <= c && c <= 'M' then chr (ord c + 13)
          else if 'N' <= c && c <= 'Z' then chr (ord c - 13)
          else if 'a' <= c && c <= 'm' then chr (ord c + 13)
          else if 'n' <= c && c <= 'z' then chr (ord c - 13)
          else c


rotc2 c =      if 'A' <= c && c <= 'M' then shift   13
          else if 'N' <= c && c <= 'Z' then shift (-13)
          else if 'a' <= c && c <= 'm' then shift   13
          else if 'n' <= c && c <= 'z' then shift (-13)
          else c

          where shift n = chr (ord c + n)


rotc3 c =      if betw 'A' 'M' then shift   13
          else if betw 'N' 'Z' then shift (-13)
          else if betw 'a' 'm' then shift   13
          else if betw 'n' 'z' then shift (-13)
          else c

          where shift  n = chr (ord c + n)
                betw x y = x <= c && c <= y


rotc4 c =  when 'A' 'M'   13
          (when 'N' 'Z' (-13)
          (when 'a' 'm'   13
          (when 'n' 'z' (-13) c)))

          where when x y n z = if x<=c && c<=y then chr (ord c + n) else z

rotc5 c = foldr shift c trips
          where shift (x,y,n) z = if x<=c && c<=y then chr (ord c + n) else z
                trips = [('A','M',13),('N','Z',-13),('a','m',13),('n','z',-13)]


--------------------
-- testing functions

ptext = "ABCLMNOPXYZ; abclmnopxyz?!"
ctext = "NOPYZABCKLM; nopyzabcklm?!"

test r = map r ptext == ctext && map r ctext == ptext

testall = map test [rotc0,rotc1,rotc2,rotc3,rotc4,rotc5, shupp 13 . shlow 13]


--------------------
-- a version with more reusable parts??


within n m f x = if (x<n || x>m) then x else f x

rel n f = (+n) . f . (\x -> x-n)

addmod k m = (`mod` m) . (+k)

shift n m k = within n m (rel n (addmod k (m-n+1)))

charly sh = chr . sh . ord

shsym a z = charly . shift (ord a) (ord z)

shupp = shsym 'A' 'Z'
shlow = shsym 'a' 'z'

rot k = map (shupp k . shlow k)


--------------------
-- parts tests

{-

    map (within 4 7 (^2)) [1..10]
    
    map (rel 5 (*2))      [1..10]
    
    map (shift 4 7 2)     [1..10]
    
    map (charly (+3))     ['a'..'z']
    
    map (shsym 'l' 'p' 2) ['a'..'z']
    
-}

--------------------
-- end of file Rots
--------------------