EX03 - If and While


Introduction

In this exercise we will build on our Caesar Cipher from EX02 to handle uppercase and lowercase strs of any length.

Before beginning, make sure that you have your EX02 working correctly and you have completed. Additionally, be sure you have completed Lessons 10, 11, and 12 before beginning this exercise.

Setup Exercise Directory

Open the course workspace in VS Code (File > Open Recent > comp110-workspace-…) and open the File Explorer pane. Expand exercises.

Right click on the word exercises and select “New Folder”.

Name the folder exactly: ex03 and create a new file called cipher.py. Copy the contents of EX02’s cipher.py into this file as a starting point.

Part 1 - Handling any alphabetic character

We want our new and improved Caesar Cipher to be able to handle both uppercase and lowercase letters. Lucky for us, python has several built-in str methods that can help us check the case of character.

isupper and islower

Python has a built-in str method, isupper, that returns True if every alphabetic character in the str is uppercase. Since we are only dealing with single-length strs in encode_char and decode_char this method will definitively tell us if we are looking at a capitalized letter or not. You can try the following code out in a REPL

>>> "c".isupper()
False
>>> "D".isupper()
True

Unsuprisingly, there is also an islower method that does just the opposite.

>>> "c".islower()
True
>>> "D".islower()
False

Refactoring encode_char and decode_char

With the built-ins methods shown above and our knowledge of if statements, we have the tools under our belt to update our _char functions to handle any character A-Z or a-z. The only difference between encoding an uppercase vs. lowercase character is the int value used to normalize our single-length str. In EX02, we used 97 since that is the ASCII code for a. Now, we still want to use 97 for lowercase letters, but in the case of an uppercase character we want to use 65. This might seem random but if we look up A here: https://en.wikipedia.org/wiki/ASCII#Printable_characters we see that its code is 65.

Functional Requirements – encode_char

  1. Have a function with the following signature:
    1. Name: encode_char
    2. Arguments: a str that can be assumed to be single-length
    3. Returns: a single-length str
  2. The new str should be the parameter given shifted one letter to the right in the alphabet, per the mapping shown above.
  3. Your function should make use of the ord and chr built-in functions.
  4. You can assume only letter characters will be tested on your function. You cannot assume whether the character will be upper or lowercase, though, so your function should handle both cases appropriately.

Functional Requirements – decode_char

  1. Have a function with the following signature:
    1. Name: decode_char
    2. Arguments: a str that can be assumed to be single-length
    3. Returns: a single-length str
  2. The new str should be the parameter given shifted one letter to the left in the alphabet, per the mapping shown above.
  3. Your function should make use of the ord and chr built-in functions.
  4. Ensure your function has the expected behavior for both uppercase and lowercase characters.

Part 2 - Handling a variable length str

The last step is to update our encode_str and decode_str functions to handle strs of any length. After this, your Caesar Cipher will be powerful enough to handle any word you give it!

To process a sequence using a loop, consider that the subscription notation expects an integer expression within the square brackets. For example, the following snippet prints every character of a str on its own line:

letters: str = "abcdefghijklmnopqrstuvwxyz"
i: int = 0
while i < len(letters):
   letter: str = letters[i]
   print(letter)
   i = i + 1

Notice using the len function to determine the length of any string allows this loop to process the letters str no matter its contents. You will need to make use of a similar strategy for encoding and decoding a str.

Functional Requirements – encode_str

  1. Have another function with the following signature:
    1. Name: encode_str
    2. Arguments: a str of any length.
    3. Returns: a str with the same length as the argument.
  2. The result of this function should be the parameter str with each letter shifted one to the right.
  3. Call encode_char inside this function for each letter of the parameter.
  4. Use a while loop with a counter variable to complete this function. Refer to lesson 11 for information on while loops.

Functional Requirements – decode_str

  1. Have another function with the following signature:
    1. Name: decode_str
    2. Arguments: a str of any length.
    3. Returns: a str with the same length as the argument.
  2. The result of this function should be the parameter str with each letter shifted one to the left.
  3. Call decode_char inside this function for each letter of the parameter.
  4. Use a while loop with a counter variable to complete this function.

Testing your program

To check that your functions work as expected, you can load your cipher file into a REPL by opening up a new REPL, and then running from exercises.ex03.cipher import encode_char, encode_str, decode_char, decode_str. From here you can practice calling your functions and seeing if the results match what you expected. Once you have completed parts 1 and 2, you should be able to try combining function calls to decode and encode.

For example, decode_char and encode_char are inverses of each other. This means if you apply encode_char to something followed by decode_char, you should end up with what you started with.

decode_char(encode_char("a")) --> returns "a"
decode_char(encode_char("A")) --> returns "A"

This same property holds for decode_str and encode_str. You should see the following behavior:

decode_str(encode_str("flex")) --> returns "flex"
decode_str(encode_str("CaEsArCiPheR")) --> returns "CaEsArCiPheR"

Style and Documentation Requirements

For the both parts of the exercise, we will manually grade your code and are looking for good choices of meaningful variable names. Your variable names should be descriptive of their purposes. We will also manually grade to check that you declared your variables with explicit types.

Once your program is working, add a docstring at the top of your file with a one-sentence description of your program’s purpose.

Then, add an __author__ variable assigned your PID as a string value after your docstring.

Lastly, there should be no magic numbers in your code. Make any magic numbers into named constants. Hint: due to our changes in refactoring encode_char and decode_char, we should have introduced another magic number into our code.

Make a Backup Commit

  1. Open the Source Control panel: View > SCM.
  2. Notice the files listed under Changes. These are files you’ve made modifications to since your last backup.
  3. Move your mouse’s cursor over the word Changes and notice the + symbol that appears. Click that plus symbol to add all changes to the next backup. You will now see the files listed under “Staged Changes”.
    • If you do not want to backup all changed files, you can select them individually. For this course you’re encouraged to back everything up.
  4. In the Message box, give a brief description of what you’ve changed and are backing up. This will help you find a specific backup (called a “commit”) if needed. In this case a message such as, “Finished Exercise 1!” will suffice.
  5. Press the Check icon to make a Commit (a version) of your work.
  6. Finally, press the Ellipses icon (…) and select “Push” to send this backed up version to your workspace repository space on GitHub.

Submit to Gradescope for Grading

All that’s left now is to hand-in your work on Gradescope for grading!

Remember, before an assignment’s deadline you can resubmit work as many times as you need to without penalty. Portions of assignments are autograded and will provide near-immediate feedback. We want you to resubmit as many times as it takes you in order to earn full autograding credit!

Login to Gradescope and select the assignment. You’ll see an area to upload a zip file. To produce a zip file for autograding, return back to Visual Studio Code.

If you do not see a Terminal, open a new Terminal.

Type the following command (all on a single line):

python -m tools.submission exercises/ex03

In the file explorer pane, look to find the zip file named “yy.mm.dd-hh.mm-submission.zip”. The “mm”, “dd”, and so on, are timestamped with the current month, day, hour, minute. If you right click on this file and select “Reveal in File Explorer” on Windows or “Reveal in Finder” on Mac, the zip file’s location on your computer will open. Upload this file to Gradescope to submit your work for this exercise.

Autograding will take a few moments to complete. For this exercise there will be 15 hand-graded points for the static types and variable names mentioned above. Thus, you should expect to score 85 out of 100 possible points on this assignment during autograding. If there are issues reported, you are encouraged to try and resolve them and resubmit. If for any reason you aren’t receiving full credit and aren’t sure what to try next, come give us a visit in office hours!