CIT 591 Assignment 5: Simple Cipher
Fall 2014, David Matuszek

Purposes of this assignment

General idea of the assignment

One of the simplest ciphers is one in which each letter is replaced by some other letter; nonletters are unchanged. For example, if every letter were replaced by the letter after it in the alphabet (with z → a), the message Attack at dawn! would become Buubdl bu ebxo!

Your assignment will be to cipher and decipher messages, using a slightly more complex scheme.

Save your program as simple_cipher.py.

Details

As above, enciphering will replace each letter in a message with a (probably) different letter, and will leave all spaces and punctuation unchanged.

Forming the secret cipher

  1. Choose a "secret word," for example, blueberry. The word should not be more than 13 characters long.
  2. Append an equal number of letters (in the example, 9) from the end of the alphabet: blueberryrstuvwxyz.
  3. Append the 26 letters of the alphabet: blueberryrstuvwxyzabcdefghijklmnopqrstuvwxyz
  4. Remove all duplicate letters, keeping only the first occurrence: bluerystvwxzacdfghijkmnopq.
  5. Map these "plain text" letters into the "cipher text" letters:
    Plain a b c d e f g h i j k l m n o p q r s t u v w x y z
      ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    Cipher b l u e r y s t v w x z a c d f g h i j k m n o p q

With this cipher, Attack at dawn! becomes Bjjbux bj ebnc!

You don't need to exactly follow the above steps, so long as the result is the same. For example, you might start by removing duplicate letters from the secret word.

Hint: It's easier to build up a new string one letter at a time, than it is to remove letters from within a string.

Making the dictionaries

Make two dictionaries: One for enciphering a message, another for deciphering an enciphered message. Each is just the reverse of the other.

Continuing the above example, the dictionary for enciphering a message would be {'a':'b', 'b':'l', 'c':'u', 'd':'e', ...}, while the one for deciphering would be {'b':'a', 'l':'b', 'u':'c', 'e':'d', ...}. (But remember, the order of entries in a dictionary is undefined and irrelevant.)

Why two dictionaries? Dictionaries contain key:value entries. It's much faster and easier to look up the value associated with a key, than it is to look up the key associated with a value. Also, keys have to be unique (you can't have two or more identical keys in the same dictionary); values do not have to be unique (although they will be in this case).

Hint: The dictionary get method can be very helpful.

Encoding and decoding

Provide two methods, encipher(secret_word, plaintext_message) and decipher(secret_word, enciphered_message). Each of these will return the result as a string; neither should print anything.

To encipher or decipher a message, simply take each character of the message in turn, use it as a key in the corresponding dictionary, and add the value to a message you are building up. If the key isn't in the dictionary, just copy it unchanged.

You also need to preserve case, so Attack becomes Bjjbux, not bjjbux. You can do this with a few simple tests, or by putting more entries in the dictionaries.

Also provide a main method which asks the user whether to encipher or decipher, asks for a secret word, asks for a message, and prints the result. This is the only method that should do any input or output.

Testing

Do test-driven development (TDD). You should have tests for every method except main.

Style

All the usual rules apply. In addition, try to keep your code as short and readable as possible, and avoid code duplication as much as possible.

Grading

We will run your main method, and will use our own unit tests for your encipher and decipher functions. We will also do spot checks for style, especially for overly long functions.

Due date

Turn your assignment in to Canvas before 6am Friday, October 3.