Skip to content

Commit

Permalink
haskell/atbash cipher
Browse files Browse the repository at this point in the history
  • Loading branch information
Vourhey committed Sep 11, 2018
1 parent 66850ff commit 6d1036e
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 0 deletions.
1 change: 1 addition & 0 deletions haskell/atbash-cipher/.solution.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"track":"haskell","exercise":"atbash-cipher","id":"846f79ab13c14f37a17b4f882ffc9486","url":"https://exercism.io/my/solutions/846f79ab13c14f37a17b4f882ffc9486","handle":"Vourhey","is_requester":true,"auto_approve":false}
89 changes: 89 additions & 0 deletions haskell/atbash-cipher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Atbash Cipher

Create an implementation of the atbash cipher, an ancient encryption system created in the Middle East.

The Atbash cipher is a simple substitution cipher that relies on
transposing all the letters in the alphabet such that the resulting
alphabet is backwards. The first letter is replaced with the last
letter, the second with the second-last, and so on.

An Atbash cipher for the Latin alphabet would be as follows:

```text
Plain: abcdefghijklmnopqrstuvwxyz
Cipher: zyxwvutsrqponmlkjihgfedcba
```

It is a very weak cipher because it only has one possible key, and it is
a simple monoalphabetic substitution cipher. However, this may not have
been an issue in the cipher's time.

Ciphertext is written out in groups of fixed length, the traditional group size
being 5 letters, and punctuation is excluded. This is to make it harder to guess
things based on word boundaries.

## Examples

- Encoding `test` gives `gvhg`
- Decoding `gvhg` gives `test`
- Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `thequickbrownfoxjumpsoverthelazydog`


## Getting Started

For installation and learning resources, refer to the
[exercism help page](http://exercism.io/languages/haskell).

## Running the tests

To run the test suite, execute the following command:

```bash
stack test
```

#### If you get an error message like this...

```
No .cabal file found in directory
```

You are probably running an old stack version and need
to upgrade it.

#### Otherwise, if you get an error message like this...

```
No compiler found, expected minor version match with...
Try running "stack setup" to install the correct GHC...
```

Just do as it says and it will download and install
the correct compiler version:

```bash
stack setup
```

## Running *GHCi*

If you want to play with your solution in GHCi, just run the command:

```bash
stack ghci
```

## Feedback, Issues, Pull Requests

The [exercism/haskell](https://github.com/exercism/haskell) repository on
GitHub is the home for all of the Haskell exercises.

If you have feedback about an exercise, or want to help implementing a new
one, head over there and create an issue. We'll do our best to help you!

## Source

Wikipedia [http://en.wikipedia.org/wiki/Atbash](http://en.wikipedia.org/wiki/Atbash)

## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
35 changes: 35 additions & 0 deletions haskell/atbash-cipher/atbash-cipher.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
-- This file has been generated from package.yaml by hpack version 0.28.2.
--
-- see: https://github.com/sol/hpack
--
-- hash: f6a46eb0c467f98162e18a6f5b8787fabfb5c5ffb5e4e8faad6f7e904e5315ee

name: atbash-cipher
version: 1.1.0.4
build-type: Simple
cabal-version: >= 1.10

library
exposed-modules:
Atbash
other-modules:
Paths_atbash_cipher
hs-source-dirs:
src
build-depends:
base
, split
default-language: Haskell2010

test-suite test
type: exitcode-stdio-1.0
main-is: Tests.hs
other-modules:
Paths_atbash_cipher
hs-source-dirs:
test
build-depends:
atbash-cipher
, base
, hspec
default-language: Haskell2010
20 changes: 20 additions & 0 deletions haskell/atbash-cipher/package.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: atbash-cipher
version: 1.1.0.4

dependencies:
- base

library:
exposed-modules: Atbash
source-dirs: src
dependencies:
- split
# - bar # want to use in your solution.

tests:
test:
main: Tests.hs
source-dirs: test
dependencies:
- atbash-cipher
- hspec
25 changes: 25 additions & 0 deletions haskell/atbash-cipher/src/Atbash.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Atbash (decode, encode) where

import Data.Char (isAlphaNum, isAlpha, ord, chr, toLower)
import Data.List.Split (chunksOf)

lettera = ord 'a'
boundary = lettera + 25

doCipher :: String -> String
doCipher [] = []
doCipher (x:xs) = if isAlpha x then
chr (boundary - ord x + lettera) : doCipher xs
else
x : doCipher xs

prepareText :: String -> String
prepareText text = map toLower $ filter isAlphaNum text

decode :: String -> String
decode cipherText = doCipher $ prepareText cipherText

encode :: String -> String
encode plainText = unwords $
chunksOf 5 $
doCipher (prepareText plainText)
1 change: 1 addition & 0 deletions haskell/atbash-cipher/stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
resolver: lts-11.1
78 changes: 78 additions & 0 deletions haskell/atbash-cipher/test/Tests.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
{-# LANGUAGE RecordWildCards #-}

import Data.Foldable (for_)
import Test.Hspec (Spec, describe, it, shouldBe)
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)

import Atbash (encode, decode)

main :: IO ()
main = hspecWith defaultConfig {configFastFail = True} specs

specs :: Spec
specs = do
describe "encode" $ for_ encodeCases $ test encode
describe "decode" $ for_ decodeCases $ test decode
where
test f Case{..} = it description $ f phrase `shouldBe` expected

data Case = Case { description :: String
, phrase :: String
, expected :: String
}

encodeCases :: [Case]
encodeCases =
[ Case { description = "encode yes"
, phrase = "yes"
, expected = "bvh"
}
, Case { description = "encode no"
, phrase = "no"
, expected = "ml"
}
, Case { description = "encode OMG"
, phrase = "OMG"
, expected = "lnt"
}
, Case { description = "encode spaces"
, phrase = "O M G"
, expected = "lnt"
}
, Case { description = "encode mindblowingly"
, phrase = "mindblowingly"
, expected = "nrmwy oldrm tob"
}
, Case { description = "encode numbers"
, phrase = "Testing,1 2 3, testing."
, expected = "gvhgr mt123 gvhgr mt"
}
, Case { description = "encode deep thought"
, phrase = "Truth is fiction."
, expected = "gifgs rhurx grlm"
}
, Case { description = "encode all the letters"
, phrase = "The quick brown fox jumps over the lazy dog."
, expected = "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"
}
]

decodeCases :: [Case]
decodeCases =
[ Case { description = "decode exercism"
, phrase = "vcvix rhn"
, expected = "exercism"
}
, Case { description = "decode a sentence"
, phrase = "zmlyh gzxov rhlug vmzhg vkkrm thglm v"
, expected = "anobstacleisoftenasteppingstone"
}
, Case { description = "decode numbers"
, phrase = "gvhgr mt123 gvhgr mt"
, expected = "testing123testing"
}
, Case { description = "decode all the letters"
, phrase = "gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt"
, expected = "thequickbrownfoxjumpsoverthelazydog"
}
]

0 comments on commit 6d1036e

Please sign in to comment.