Search code examples
pythoncaesar-cipher

Caesar Cipher - Can't get working


I've got this task for my Python class that I am supposed to do, however I can't seem to print the end result. The aim of the task is to create a program that:

  • Allows one to encrypt or decrypt using an offset of the users choice
  • It should then take that information and move the letters of the subject word by that offset value, giving you the encrypted or decrypted product

The problem is that my code won't print the result, and I can't see what's wrong with it.

Here is my code:

 Choice = input("Would you like to decrypt or encrypt a message? Please 
enter 'E' or 'D': ")
Message = input("Enter text to Cipher: ")
Offset = int(input("Please enter your offset: "))
Encrypt = ''
Decrypt = ''

if Choice == "e".upper():
    for character in Message:
        x = ord(character)
        Encrypt += chr(Offset + x)
    print (Encrypt)
if Choice == "d".upper():
    for character in Message:
        x = ord(character)
        Decrypt += chr(Offset - x)
    print (Decrypt)

Why aren't I getting the output of the print()s?


Solution

  • First, the obvious: These aren't the paths you're looking for

    Your "if Choice" selection is wrong, so you are likely never executing the path you expect. You never coerced the input, so your if statements either need to be if Choice.upper() == 'E': or, more explicitly, if (Choice == 'E') or (Choice == 'e'):. I use both for example below.

    Next, your actual procedure: Caesar ciphers ROTATE

    You are not adhering to the rotational nature of a Caesar cipher. Ceaser ciphers are like 12-hour clocks. "4 hours after 11" is not "15 o'clock", it is "3 o'clock", which in Python is: (11 + 4) % 12

    With that in mind, what is the range of ASCII characters? How many are there? Are you including the non-character-but-printables? Are you including the entire range of valid Unicode? (Including unicode is, by the way, probably very close to impossible because of the nature of how values are constructed from pages, among other issues.)

    So the simple case is ASCII values, printable characters between 32 through 126. (Here is a chart for reference: ASCII Table)

    That gives us 126 - 32 = 94 characters in the valid set, analogous to the 12 valid hours in a 12-hour clock. It also means that our bottom value is 32, meaning nothing can be below that value.

    Our cipher procedure then looks something like this:

    1. accept the shift from the user
    2. subtract 32 from a given value
    3. adjust it by the shift value
    4. get the real shift by taking the shifted value modulo 94
    5. add back 32

    The decipher procedure is then the inverse operation.

    Choice = input("Would you like to decrypt or encrypt a message?\nPlease enter 'E' or 'D': ")
    Message = input("Enter text to Cipher: ")
    Offset = int(input("Please enter your offset: "))
    Encrypt = ''
    Decrypt = ''
    
    if (Choice == 'e') or (Choice == 'E'):
        for character in Message:
            x = ord(character) - 32
            Encrypt += chr(((Offset + x) % 94) + 32)
        print(Encrypt)
    if Choice.upper() == 'D':
        print("You didn't think I was going to do all your homework for you, right?")
    

    Obviously this can be adjusted to expand/reduce the valid range of inputs or outputs. Most example Caesar ciphers only use [A-Z] as valid characters, so the range is 26 and the bottom value is 65, and you'll have to perform your operations on Message.upper(), etc. But the principle is the same.