The Problem

We have created a Caesar cipher before in class (also known as a simple substitution cipher). In this problem we will bundle up the functionality of Caesar ciphers in a Cipher object. A Cipher object is instantiated with a text string. The object will remember the initial text string as the text converted to lowercase and with all nonalpabetic characters removed. You must import and use the regular expression module re to do the remove using the sub() method. The initial string is what is termed "the clear" or unencoded message. The object also remembers the last encoded version of the text string. The initial value of the encoded string is simply the clear.

A Cipher object can be printed using just regular print because it will have a __str__ method. Printing the Cipher object will print the encoded message.

The Cipher object as a variable named __alpha which is the 26 lowercase letters in order: "abcdefghijklmnopqrstuvwxyz" Note the "double underbar" or "dunder" to make the name private to the class.

It can then have Caesar ciphers applied to the text or deciphers. The method caesar(keyword) will cause the current value of the ENCODED string to be encoded using the keyword. More about keyword later. But it is important to see that multiple applications of caesar ciphers can create a "pipeline" of ciphers. There is a corresponding uncaesar(keyword) method. The reset method will set the encoded string back to the clear.

Your object must have two static methods. The first is __cleantext(text). This method will convert text to lower case and remove all non-alphabetic characters and return that string. Use the @staticmethod decorator. You will use this method clean up the text for keywords and the initial clear text. Note the "double underbar" or "dunder" used with cleantext. The intent is for this procedure not to be called outside of the object.

You object will have a makeKey(keyword). This will make 26 character key given a keyword or phrase. It first uses cleantext to change class and delete unwanted characters. It then removes duplicate letters in keyword and attach them to the end of a string of the remaining letters. For example makeKey("abcba") would give "defghijklmnopqrstuvwxyzabc" and makeKey("dog") would give "abcefhijklmnpqrstuvwxyzdog" If no keyword supplied then makeKey() will produce a random keyword by shuffling the alphabet. You must include the random module to get the shuffle feature.

getLastKeyword() will return the last keyword used in caesar. It is initialized to None and reset to None in both reset() and uncaesar(keyword) routines. We will not set it to the keyword used to decode a message, only encode it. You will need to keep the lastKeyword value in the object.

Here is an example:

    sometext = "The wind of heaven is that which blows between a horse's ears."
    key = Cipher.makeKey("syzygy")
    print(key, len(key))
    c = Cipher(sometext)
    print(0, c)
    c.caesar("Cats are the enemy!")
    print(1, c)
    c.caesar("My dog has fleas")
    print(2, c)
    c.uncaesar("My dog has fleas")
    print(1, c)
    c.uncaesar("Cats are the enemy!")
    print(0, c)
    print()
    c.caesar("Ravenous Bugblatter Beast of Traal")
    print(c)
    print(c.getLastKeyword())
    c.reset()
    print(c)
    print(c.getLastKeyword())
    print("Random key")
    c.caesar()
    print(c)
    c.uncaesar(c.getLastKeyword())
    print(c)
    print(str(c)==Cipher._Cipher__cleantext(sometext))
which gives this output:
0 thewindofheavenisthatwhichblowsbetweenahorsesears
1 slihowgxjlibeiwotslbshloflduxhtdishiiwblxatitibat
2 ovrqzspftvrckrszgovcoqvznvjhfqgjroqrrscvfbgrgrcbg
1 slihowgxjlibeiwotslbshloflduxhtdishiiwblxatitibat
0 thewindofheavenisthatwhichblowsbetweenahorsesears

upjgqriakpjcbjrqoupcugpqhpdyagodjugjjrcpanojojcno
Ravenous Bugblatter Beast of Traal
thewindofheavenisthatwhichblowsbetweenahorsesears
None
Random key
vftczhpmgftjbthzxvfjvcfzwfklmcxktvctthjfmdxtxtjdx
thewindofheavenisthatwhichblowsbetweenahorsesears
True

Testing

Your object will be in a file called cipher.py (note all lowercase). I will import your Cipher object in a test python script:

from cipher import Cipher

Submission

Homework will be submitted as an uncompressed tar file that contains no subdirectories. The tar file is submitted to the class submission page. You can submit as many times as you like. The LAST file you submit BEFORE the deadline will be the one graded. Absolutely, no late papers. For all submissions you will receive email at your uidaho address showing how your file performed on the pre-grade tests. The grading program will use more extensive tests, so thoroughly test your program with inputs of your own. Your code should compile and run without runtime errors such as seg faults or Python errors. If it doesn't it is considered nearly ungradable.

If you have tests you really think are important or just cool please send them to me and I will consider adding them to the test suite.