{-|

Module      : Caesar
Description : Caesar cipher
Copyright   : © Frank Jung, 2022
License     : GPL-3

Code from <https://www.manning.com/books/haskell-bookcamp Haskell Bookcamp>
by Philipp Hagenlocher

This is my version of a simplified
<https://en.wikipedia.org/wiki/Caesar_cipher Caesar Cipher>.

-}

module Caesar ( caesar
              , isAscii
              , asciiRot
              ) where

import           Data.Char (chr, ord)

-- | Limited ASCII character set, includes all printable characters except
-- the space character.
isAscii :: Char -> Bool
isAscii :: Char -> Bool
isAscii Char
c = Int
33 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
oc Bool -> Bool -> Bool
&& Int
oc Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
126
  where oc :: Int
oc = Char -> Int
ord Char
c

-- | Rotate a ascii character.
-- 94 = 126 - 33 + 1
-- 33 is starting offset of printable characters (after space)
asciiRot :: Int -> Char -> Char
asciiRot :: Int -> Char -> Char
asciiRot Int
n Char
x
  | Char -> Bool
isAscii Char
x = Char
rotate
  | Bool
otherwise = Char
x
  where rotate :: Char
rotate = Int -> Char
chr (Int -> Char) -> Int -> Char
forall a b. (a -> b) -> a -> b
$ (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Char -> Int
ord Char
x Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
33) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
94 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
33

-- | Simple implementation of Caesar Cipher.
caesar :: Int -> String -> String
caesar :: Int -> String -> String
caesar Int
n = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Char -> Char
asciiRot Int
n)