Lab 7: Strings, ASCII Encoding, and Formatting

Goals

After the lab, you should be proficient at

Objective: Review

Review the slides for today's lab.

Objective: Set Up

Objective: Programming in Python

We'll practice writing several Python programs, each in their own text file.

Your programs will be graded on correctness, style, efficiency, and how well you tested them. Make sure you adhere to the good development and testing practices we discussed in class. Your code should be readable and your output should be useful and well-formatted.

After you've developed a correct solution to each program, restart IDLE or close and reopen the IDLE "shell" by running the program again (using F5), demonstrate that the program works using several good test cases, and save the output to a file named lab7_x.out, where x is the problem number.

  1. (10 pts) Using a for loop, display a diagonal line that looks like:
    \
     \
      \
       \
        \
    

    Think about the pattern of what is getting printed. (No box, of course.)

    After you have that working, have the user enter the size of the diagonal line and draw a line of the appropriate size.

  2. Caesar Cipher. A Caesar cipher is a simple substitution cipher based on the idea of shifting each letter of a text message a fixed number (called the key) of positions in the alphabet. Recall that the alphabet wraps around. For example, 'z' with a key of 5 is encoded as 'e'.

    Rhetorical question: why is the limit on keys between -25 and +25?

    Pedagogical Overview: We're going to build up the Caesar cipher code in a couple of steps but all in one file. By the end of the term, you should feel comfortable with breaking up a problem yourself. In the meantime, we'll go through a few examples of breaking up a program into components that are easier to solve. You can peek at the last step in this problem to see where we're going.

    • (15) Write a function called encrypt_letter that takes as parameters a lowercase letter and a key and returns the letter encrypted. For example, if you call the function encrypt_letter('a', 1), the function should return 'b'. Similarly, if you call the function encrypt_letter('b', -1), the function should return 'a'.

      As we've been doing, write the function and then test it using the test.testEqual function in a test function called test_encrypt_letter. What are good test cases for this function? You can and should have a good variety of tests for this function. You want to make sure that this function works because you're building on it for the rest of the problem.

    • (15) Add a function called encrypt_message that takes a message containing only lowercase letters, spaces, and punctuation to encrypt and a key as parameters and returns the encrypted message. (Do not delete any of the code from the last problem.) For example, if you call encrypt_message("w and l!", 1), the function should return "x boe m!". As before, create a function that tests this function. What are good test cases for this function?

      ! The function you created in the last step will likely be helpful to call. (Read: you should call that function in this function.) You should NOT modify the function you wrote in the previous problem. You should have already tested that function thoroughly, so you know that it's working, so don't modify that function. Of course, if you find problems with that function, then fix the function and improve your test function to verify the correctness of the function.

    • (10) Add a function called is_valid_character that takes a character as a parameter and returns True if the character is a space, lowercase letter, or punctuation; otherwise, it returns False. Leverage the string module (recall the textbook reading and the review in class) and appropriate str methods and operations. Test your function. (Hopefully, you didn't need the reminder.)
    • (10) Add a function that checks that a string is valid input for encryption. Your function is called is_encryptable_message. It takes as a parameter the string to encrypt. It returns True if the string is a valid string for encoding, i.e., it contains only lowercase letters, spaces, and punctuation. Otherwise, it returns False.

      Note how the problem is phrased. It is not sufficient to check if there are digits or uppercase letters in the message. There are characters that you may not have thought about. The important part is that you want the string to only contain lowercase letters, spaces, and punctuation.

      Example test cases:

          test.testEqual( is_encryptable_message("z"), True )
          test.testEqual( is_encryptable_message(" "), True )
          test.testEqual( is_encryptable_message("this"), True )
          test.testEqual( is_encryptable_message("this is"), True )
          test.testEqual( is_encryptable_message("this!"), True )
          test.testEqual( is_encryptable_message("1"), False )
          test.testEqual( is_encryptable_message("this is not valid1"), False )
          test.testEqual( is_encryptable_message("Valid"), False )
          test.testEqual( is_encryptable_message("invalid\nmessage"), False )

      You should put these test cases and more, as appropriate into a function that tests this function.

    • (14) Implement an interactive interface to the Caesar Cipher functionality. The program's main function will take as input a phrase to encrypt and a key and will display the encrypted phrase.

      After making sure the "typical" behavior works, add error handling:

      • Your program should enforce that the user enters an "encryptable" string (by our rules) by repeatedly prompting for the string until it is valid.
      • Your program should handle the error case where the user-supplied key is not in the valid range by repeatedly prompting for the key until it is valid.

      Give your neighbor a message to decrypt, along with the original key used to encrypt the message. Put your neighbor's name, the original message, and the decrypted message in comments in your finished program, right under the high-level description. If others aren't around, decrypt this message, which I generated using the key 12: bkftaz ue yk rmhadufq bdasdmyyuzs xmzsgmsq! When you demonstrate your program, include decoding the message in your saved output.

      Your program should produce the following interaction with the user:

      This program encrypts and decrypts Ceasar ciphers.
      
      Enter message: i like the lions at the zoo.
      Enter an integer key (between -25 and +25): 1
      The encrypted text is: j mjlf uif mjpot bu uif app. 
      
      This program encrypts and decrypts Ceasar ciphers.
      
      Enter message: j mjlf uif mjpot bu uif app. 
      Enter an integer key (between -25 and +25): -1
      The encrypted text is: i like the lions at the zoo. 
      
      This program encrypts and decrypts Ceasar ciphers.
      
      Enter message: I like the lions at the zoo.
      Error: Provided text is not encryptable.
      It can only contain lowercase letters, spaces, and punctuation.
      
      Please enter message: I like the lions at the zoo!
      Error: Provided text is not encryptable.
      It can only contain lowercase letters, spaces, and punctuation.
      
      Please enter message: i like the lions at the zoo.
      Enter an integer key (between -25 and +25): 26
      Error: key is not valid. Key must be between -25 and 25.
      
      Enter an integer key (between -25 and +25): 1
      The encrypted text is: j mjlf uif mjpot bu uif app. 
      
  3. (10 pts) Copy lab2/lab2_2.py into this directory and name it appropriately for this lab. Update the high-level description appropriately. Modify it such that the program always displays the money values to 2 decimal places. Note the change in the output (e.g., the use of the $).

    (You may want to "clean up" your original program to get rid of extra output.)

    Example program runs should look like:

    Bill amount in dollars: 162.29
    Percent tip: 15
    Number of people: 8
    
    The tip is $24.34.
    The total cost is $186.63.
    The cost per person is $23.33.
    

    Bill amount in dollars: 20
    Percent tip: 20
    Number of people: 3
    
    The tip is $4.00.
    The total cost is $24.00.
    The cost per person is $8.00.
    
  4. (16) Write a program that creates a table of Olympic competition running distances in meters, kilometers, yards, and miles. The following distances should be used: 100 m, 200 m, 400 m, 800 m, and 1600m.

    Note that 1 m = .001 km = 1.094 yds = .0006215 mi

    Calculate and display the results, formatted in the following manner:

    
    Meters   Kilometers     Yards    Miles
    ---------------------------------------
       100        0.100     109.4    0.062
       200        -----     -----    -----
       400        -----     -----    -----
       800        -----     -----    -----
      1600        -----    ------    -----
    

    Note: Make sure your output is formatted exactly as above except that you will have all the converted values filled in. Note the spacing of the columns, the justification of the columns, the precision, ...

    Your final solution should not have a lot of repeated code. How can you solve this problem without repeated code? Notice the pattern.

    (You should not use a list to solve this problem.)

Extra Credit

We can provide problem clarifications, but try to solve extra credit problems on your own.

Vigenere Cipher (up to 8 pts)

Write a program that implements a Vigenere cipher. Name the Python file vigenere_ec.py. You should be able to leverage your previous code to help you solve this problem. Some example output:

This program encrypts Vigenere ciphers.

Enter some text: the eagle flies at midnight
Enter a keyword: key

Encrypted text: dlc iyqpc jjsiq er qgnrgqlr

More points will be awarded for programs that demonstrate good programming practices (e.g., use of functions, code reuse, programmatic testing).

Comparing Solutions (up to 7 pts)

In a file called comparison_ec.py, copy the is_valid_character and is_encryptable_message functions from problem 2.

Create a new function called is_encryptable_message2 with the same interface and doc string that does not use the is_valid_character function. Instead, it should implement the functionality within this function (only). Test the new function to confirm it works the same as the original implementation.

Analysis. In comments, compare the two versions of the is_encryptable_message functions. How do they compare in terms of conceptual complexity? Readability/understandability? Maintainability (i.e., being able to update them if requirements change)?

Finishing up: What to turn in for this lab

    Note that each command links to a page with more information about using the command.

  1. Create the printable lab assignment, using the createPrintableLab command.
  2. View your file using the evince command.
  3. Check that the PDF contains all (and only) the necessary files.
  4. Print the file from evince. You can print to other printers if there are issues with the computer science printers (which do not cost you anything to print computer science work).
  5. Submit your lab directory into your turnin directory.
  6. Log out of your machine when you are done.

Ask well before the deadline if you need help turning in your assignment!

Grading (100 pts)