Assignment #2: Coded Messages

With the amount of information flowing across the internet, keeping data secure is an important concern. Keeping usernames, passwords, bank accounts, health records, etc. safe requires constant work.

Encryption refers to any process that converts information into a secret code that hides its meaning from prying eyes. For example, messages can be encrypted on one user’s device, sent to another user, and then changed back into plain text on the second device. Anyone spying on the message mid-stream will see unreadable content.

For this assignment, you will create a program that changes plain text messages into coded ones. Your program will also decode messages to produce readable text.

Note

If your teacher added you to a repl.it classroom or a Trinket course, complete Assignment #2 there.

If you are NOT enrolled in a repl.it classroom or Trinket course, you can find a copy of the starter code here:

  1. repl.it starter code

  2. Trinket starter code

Requirements

By the end of this assignment, your program will:

  1. Prompt the user for a message and a shift value.

  2. Ask the user to either encrypt or translate the message.

  3. Convert the user’s plain text message to a coded one (or vice versa).

  4. Display the original message and the changed one.

Part 1: Simple Letter Shift

You will use a basic encryption tool, called the Caesar Cipher, to encode a message. This process takes each letter in a message and replaces it with a different one. The new letters are all shifted a certain number of spaces in the alphabet compared to the originals.

Image showing how the Caesar cipher shits letters in the alphabet.

In this case, each original letter is shifted 2 places to the right in the alphabet.

Open a new project in your code editor and complete the following tasks.

The alphabet_position Function

  1. Define a function called alphabet_position with one parameter. The parameter receives a string containing a single letter.

  2. The function returns the index of that letter within the alphabet.

  3. The function should be case-insensitive. Capital and lowercase letters return the same result.

    Sample Results

    letter

    Return Value

    a or A

    0

    d or D

    3

    z or Z

    25

  4. Don’t forget to test your function! In the main() function, call alphabet_position and send in different letters as arguments. Be sure to print the returned result to check your code.

Tip

  1. You can assume the argument sent to the function will be a single letter. Do not worry about what to do with longer strings or non-letter characters.

  2. alphabet_position should NOT print anything. It needs to return a value instead.

The shift_character Function

  1. Define the function shift_character(char, shift) with two parameters. char accepts a character (a string of length 1) and shift accepts an integer value.

  2. If char is a letter, the function returns a different one. The new letter will be shift places to the right in the alphabet.

  3. The case of the original letter and the returned value should match. For example, shift_character("A", 1) returns "B", instead of "b".

  4. If char is NOT a letter, then the function returns the same character.

    Sample Results

    char

    shift

    Return Value

    a

    13

    n

    D

    4

    H

    z

    3

    c

    J

    30

    N

    ?, 6, &, etc.

    (any integer)

    ?, 6, &, etc. (no change for non-letter characters)

  5. Test your function! In main(), call shift_character and send in different characters and shift values. Be sure to print the letter returned to make sure your code works properly before moving on.

Tip

  1. You should make use of your alphabet_position function! Thinking in terms of index values helps.

  2. Notice in the Sample Results table that the function wraps around when it reaches the end of the alphabet. If a shift moves the program past the letter 'z' (index value 25), it moves back to the start of the alphabet and continues counting with 'a' (index value 0).

  3. The modulus operator will be a BIG help here to keep the index values in the range 0 - 25.

The build_code_dict Function

  1. Define the function build_code_dict that takes one parameter (an integer).

  2. The function will build and return a dictionary. Each of the keys will be a letter from the alphabet. Each of the values will also be a letter, but shifted to the right a certain number of places. How many places? That depends on the integer sent to the function.

    Hints: The accumulator pattern strikes again! Also, think about calling the shift_character function to keep your code DRY.

  3. The returned dictionary should include keys for BOTH lower and uppercase letters.

  4. Test your function! In main(), call build_code_dict and send in different integer values. Be sure to print the returned dictionary to check the results.

    Sample Results

    Function Call

    Returned Dictionary

    build_code_dict(1)

    {‘a’: ‘b’, ‘b’: ‘c’, ‘c’: ‘d’, ‘d’: ‘e’, ‘e’: ‘f’, ‘f’: ‘g’, ‘g’: ‘h’, ‘h’: ‘i’, ‘i’: ‘j’, ‘j’: ‘k’, ‘k’: ‘l’, ‘l’: ‘m’, ‘m’: ‘n’, ‘n’: ‘o’, ‘o’: ‘p’, ‘p’: ‘q’, ‘q’: ‘r’, ‘r’: ‘s’, ‘s’: ‘t’, ‘t’: ‘u’, ‘u’: ‘v’, ‘v’: ‘w’, ‘w’: ‘x’, ‘x’: ‘y’, ‘y’: ‘z’, ‘z’: ‘a’, ‘A’: ‘B’, ‘B’: ‘C’, ‘C’: ‘D’, ‘D’: ‘E’, ‘E’: ‘F’, ‘F’: ‘G’, ‘G’: ‘H’, ‘H’: ‘I’, ‘I’: ‘J’, ‘J’: ‘K’, ‘K’: ‘L’, ‘L’: ‘M’, ‘M’: ‘N’, ‘N’: ‘O’, ‘O’: ‘P’, ‘P’: ‘Q’, ‘Q’: ‘R’, ‘R’: ‘S’, ‘S’: ‘T’, ‘T’: ‘U’, ‘U’: ‘V’, ‘V’: ‘W’, ‘W’: ‘X’, ‘X’: ‘Y’, ‘Y’: ‘Z’, ‘Z’: ‘A’}

    build_code_dict(10)

    {‘a’: ‘k’, ‘b’: ‘l’, ‘c’: ‘m’, ‘d’: ‘n’, ‘e’: ‘o’, ‘f’: ‘p’, ‘g’: ‘q’, ‘h’: ‘r’, ‘i’: ‘s’, ‘j’: ‘t’, ‘k’: ‘u’, ‘l’: ‘v’, ‘m’: ‘w’, ‘n’: ‘x’, ‘o’: ‘y’, ‘p’: ‘z’, ‘q’: ‘a’, ‘r’: ‘b’, ‘s’: ‘c’, ‘t’: ‘d’, ‘u’: ‘e’, ‘v’: ‘f’, ‘w’: ‘g’, ‘x’: ‘h’, ‘y’: ‘i’, ‘z’: ‘j’, ‘A’: ‘K’, ‘B’: ‘L’, ‘C’: ‘M’, ‘D’: ‘N’, ‘E’: ‘O’, ‘F’: ‘P’, ‘G’: ‘Q’, ‘H’: ‘R’, ‘I’: ‘S’, ‘J’: ‘T’, ‘K’: ‘U’, ‘L’: ‘V’, ‘M’: ‘W’, ‘N’: ‘X’, ‘O’: ‘Y’, ‘P’: ‘Z’, ‘Q’: ‘A’, ‘R’: ‘B’, ‘S’: ‘C’, ‘T’: ‘D’, ‘U’: ‘E’, ‘V’: ‘F’, ‘W’: ‘G’, ‘X’: ‘H’, ‘Y’: ‘I’, ‘Z’: ‘J’}

    build_code_dict(33)

    {‘a’: ‘h’, ‘b’: ‘i’, ‘c’: ‘j’, ‘d’: ‘k’, ‘e’: ‘l’, ‘f’: ‘m’, ‘g’: ‘n’, ‘h’: ‘o’, ‘i’: ‘p’, ‘j’: ‘q’, ‘k’: ‘r’, ‘l’: ‘s’, ‘m’: ‘t’, ‘n’: ‘u’, ‘o’: ‘v’, ‘p’: ‘w’, ‘q’: ‘x’, ‘r’: ‘y’, ‘s’: ‘z’, ‘t’: ‘a’, ‘u’: ‘b’, ‘v’: ‘c’, ‘w’: ‘d’, ‘x’: ‘e’, ‘y’: ‘f’, ‘z’: ‘g’, ‘A’: ‘H’, ‘B’: ‘I’, ‘C’: ‘J’, ‘D’: ‘K’, ‘E’: ‘L’, ‘F’: ‘M’, ‘G’: ‘N’, ‘H’: ‘O’, ‘I’: ‘P’, ‘J’: ‘Q’, ‘K’: ‘R’, ‘L’: ‘S’, ‘M’: ‘T’, ‘N’: ‘U’, ‘O’: ‘V’, ‘P’: ‘W’, ‘Q’: ‘X’, ‘R’: ‘Y’, ‘S’: ‘Z’, ‘T’: ‘A’, ‘U’: ‘B’, ‘V’: ‘C’, ‘W’: ‘D’, ‘X’: ‘E’, ‘Y’: ‘F’, ‘Z’: ‘G’}

Note

Remember that dictionaries are unordered collections. The key/value pairs in your results might be in a different order than the examples, and that is OK.

Part 2: Code and Decode Messages

Now that your Part 1 functions all work, you are ready to create coded messages! Before you dive in, however, remove any print statements you used to test those functions.

The encrypt_with_shift Function

  1. Define the function encrypt_with_shift(text, shift). The text parameter accepts a string and shift accepts an integer. text will be the message to convert to code, and shift will be the number of spaces to shift each letter in the alphabet.

  2. Just in case no shift value gets sent to the function, set its default value to be 1.

  3. Inside the function, call build_code_dict and use shift as the argument. Assign the returned dictionary to a variable.

  4. Use the accumulator pattern to build up the coded message.

    1. Define a variable to hold the coded message.

    2. Loop through each character in text.

    3. If the character is a key in the code dictionary, add its value to the coded message. If the character is NOT a key in the dictionary, add the original character to the message.

  5. Return the final, coded message.

The decrypt Function

The encrypt_with_shift function codes a message by shifting all of the letters to the right in the alphabet. To translate a coded message back into clear text, you must shift the letters to the left the same number of steps.

  1. Define a decrypt function that takes a coded message and a shift value as the parameters.

  2. The function returns the translated message.

  3. Make this happen.

  4. Hints:

    1. There’s no rule that says shift values have to be positive.

    2. Remember that functions can call other functions.

    3. The decrypt function can be completed with only a small number of statements.

Test Your Functions!

  1. In main(), define the message and shift_by variables. Assign values to each one.

  2. Call the encrypt_with_shift function and use the two variables as the arguments. Assign the returned (coded) message to another variable.

  3. Print the coded message.

  4. Call the decrypt function and send in the coded message and shift_by as the arguments. Assign the returned (translated) message to another variable.

  5. Print the translated message.

Sample Results

Message

Function

Shift

Returned Message

LaunchCode

encrypt_with_shift

13

YnhapuPbqr

Hello, World!

encrypt_with_shift

5

Mjqqt, Btwqi!

Ktocji MJXFN!

decrypt

21

Python ROCKS!

Hsz dljd T’x yze l nzopc? Hlens xp aczgp espx hczyr!

decrypt

11

Who says I’m not a coder? Watch me prove them wrong!

Part 3: Add User Input

The next step is to make your program interactive.

  1. In main(), code some input statements so the user can enter a message and a shift value.

  2. Ask the user to choose to encrypt or translate the message.

  3. Print the original message and the result.

Part 4: Create a Module

The alphabet_position and shift_character functions might be useful for other programs. Move them into a module!

  1. Create a new file in your project. Remember to add .py to the end of the filename.

  2. Cut and paste the two functions into the new file. alphabet_position and shift_character should no longer appear in the main.py file!

  3. Try running your program. It should NOT work! Read the error message carefully.

  4. In main.py import the required function from the module, then run your program again. Use any error messages to guide you as you get your code working again.

Sample Output

Your output does not have to look exactly like the samples, but it should be close.

Enter a message: LaunchCode
Enter a shift value: 13
Would you like to [e]ncrypt or [t]ranslate the message? e

Original message: LaunchCode
New message: YnhapuPbqr
Enter a message: Ktocji MJXFN!
Enter a shift value: 21
Would you like to [e]ncrypt or [t]ranslate the message? T

Original message: Ktocji MJXFN!
New message: Python ROCKS!

Bonus Mission

The Caesar Cipher works fine, but it is VERY easy to decode. Add another function to your program that takes a coded message and returns all possible outcomes for how the message can be translated back into English.

For example:

Coded Message: Udymts fuuwjsynhj, dtz fwj.
Translations:
   Shift 1: Tcxlsr ettvirxmgi, csy evi.
   Shift 2: Sbwkrq dssuhqwlfh, brx duh.
   Shift 3: Ravjqp crrtgpvkeg, aqw ctg.
   Shift 4: Qzuipo bqqsfoujdf, zpv bsf.
   Shift 5: Python apprentice, you are.  <-- Scan output for clear text.
   Shift 6: Oxsgnm zooqdmshbd, xnt zqd.
   Shift 7: Nwrfml ynnpclrgac, wms ypc.
   etc.

Back in main() call the function, send it a coded message, and print each result so you can spot the correct translation.

Q iu bpm Xgbpwv axg uiabmz.

Final Checks

Before submitting your assignment, make sure your program:

  1. Works.

  2. Only displays the expected output and NOT any of the function test results.

  3. Contains no loose code statements (statements placed outside of any function).

  4. Includes enough comments to describe to a non-coder what each part of the program does.

  5. Survives unexpected inputs (e.g. if the user enters a letter instead of a number when asked for a shift value).