CS21 Lab3: Boolean and Strings

Due 11:59pm Tuesday, February 10

Run update21, if you haven't already, to create the cs21/labs/03 directory. handin21 looks for your lab 3 assignments in the cs21/labs/03 directory, so make sure you create your python programs in there:

$ cd cs21/labs/03
$ gvim classyear.py

Your programs are graded on both correctness and style. Please review the comments regarding programming style on the main page.

Class Year Calculator

If you are graduating this year, you are a senior; if you graduate next year, you are a junior; etc. Write a program that asks the user for the current year and then asks the user for the year that they graduate in. In response, you tell the user their class year. Here are some sample runs of a working program:

$ python classyear.py
Enter the current year: 2009 
Enter your graduation year: 2010
You are a junior.

$ python classyear.py
Enter the current year: 2005 
Enter your graduation year: 2007
You are a sophomore.
Optionally, you can extend the program to print out informative messages if the user enters a value that is out of the valid range of a typical four-year college education. For example:
$ python classyear.py
Enter the current year: 2009 
Enter your graduation year: 2014
You are not yet in college.

$ python classyear.py
Enter the current year: 2009 
Enter your graduation year: 2008
You already graduated.
Day of Year
[Problem 13 in Chapter 7 of Zelle text] The days of the year are sometimes numbered 1 through 365 (or 366 during leap years) starting from January 1st. The day of the year can be computed using the following steps:
  1. Begin by computing dayNum = 31*(month-1) + day
  2. Next, if the month is after February, subtract (4*month+23)/10 from dayNum
  3. Finally, if the year is a leap year and the date is after February, add 1 to dayNum
In general, a year is a leap year if the year is divisible by 4, but not divisible by 100. However a year that is divisible by 400 is a leap year. For details on why leap years have these funny 100 and 400 year exceptions, see a description from howstuffworks.

Write a program dayOfYear.py that prompts the user for a date in mm/dd/yyyy format and prints the corresponding day of year. You can use split with a / delimiter to break the user input into a list of strings corresponding to the month, day and year. You will need to convert pieces of the list into integers to do the math.


>>> from string import *     
>>> dayString = "2/10/2009"
>>> parts = split(dayString, "/")
>>> print parts
['2', '10', '2009']

$ python dayOfYear.py
Enter a date in mm/dd/yyyy format: 2/10/2009
2/10/2009 is day number 41
$ python dayOfYear.py
Enter a date in mm/dd/yyyy format: 3/1/2008
2/10/2009 is day number 61
$ python dayOfYear.py
Enter a date in mm/dd/yyyy format: 3/1/2000
2/10/2009 is day number 61
$ python dayOfYear.py
Enter a date in mm/dd/yyyy format: 3/1/1900
2/10/2009 is day number 60
$ python dayOfYear.py
Enter a date in mm/dd/yyyy format: 3/1/2009
2/10/2009 is day number 60
$ python dayOfYear.py
Enter a date in mm/dd/yyyy format: 1/1/2009
2/10/2009 is day number 1
$ python dayOfYear.py
Enter a date in mm/dd/yyyy format: 1/1/2008
2/10/2009 is day number 1
You do not need to check if the date the user entered is valid, though you may add this as an optional extension.
Cyclic Cipher

Write a program, in a file named encode.py, that asks the user to enter a phrase and a cyclic shift value, and produces an encoded string by applying the cyclic cipher method to just the alphabetic characters in the phrase. Your solution should encode ONLY upper and lower case characters in the phrase. Several hints at the end of this document help guide you towards a solution. It is highly recommended that you follow the hints and test your program incrementally.

A cyclic cipher, with a shift value of 3 will encode the character 'a' as the character 'd', the character 'b' as 'e', and so on (each character's encoding is shifted 3 characters to the right). A cyclic cipher wraps the encoding around the alphabetic characters, so that in this example, 'w' is encoded as 'z', 'x' is encoded as 'a', 'y' is encoded as 'b', and 'z' is encoded as 'c'. You can think of this as encoding where the alphabet is arranged in a circle, and the shift amount tells you how many places in one direction to move to find the encoding of any letter of the alphabet.

Here is what a few runs of your program might look like:

$ python encode.py
This program encodes a phrase using a cyclic cipher
Enter a phrase: Hello there, Zoe!  What is happening???
Enter a shift value: 4
The encoded phrase is: Lipps xlivi, Dsi!  Alex mw lettirmrk??? 

$ python encode.py
This program encodes a phrase using a cyclic cipher
Enter a phrase: Lipps xlivi, Dsi!  Alex mw lettirmrk???
Enter a shift value: -4
The encoded phrase is: Hello there, Zoe!  What is happening???

$ python encode.py
This program encodes a phrase using a cyclic cipher 
Enter a phrase: yee ha!!!
Enter a shift value: 1000
The encoded phrase is: kqq tm!!!
Hints for solving: I'd suggest approaching this problem in the following way:
  1. First, write the program so that the user enters a phrase, and your program constructs a new string consisting of all the characters in the original phrase where every alphabetic character is replaced with the character 'x' (all other non-alphabetic characters stay the same in the new string). For example, if the user enters the phrase "To be, or not to be." your program will produce a new string "xx xx, xx xxx xx xx.".
  2. Once that works, next see if you can produce an encoded string where the alphabetic characters are encoded by doing only the shift part of the cyclic cipher (don't do the cyclic, wrap-around, part of the encoding yet). For example, a shift value of 4 will encode 'a' as 'e', 'b' as 'f', ..., 'u' as 'y', 'v' as 'z', 'w' as whatever the character after 'z' is in the ascii encoding, 'x' as whatever the character is two beyond 'z' in the ascii encoding, ...
  3. Once that works, add in code to do the cyclic part of the shift. For example, a shift value of 4 will encode 'a' as 'e', 'b' as 'f', ..., 'v' as 'z', 'w' as 'a', 'x' as 'b', ...

    You will need to use the mod operator % to do a cyclic shift. Here is an example of a similar problem. The days of the week are cyclical. Suppose we assign the following numeric code to the days of the week:

    0 Sunday
    1 Monday
    2 Tuesday
    3 Wednesday
    4 Thursday
    5 Friday
    6 Saturday
    
    If we wish to determine what day of the week is 100 days from Tuesday, we can look at the code for Tuesday (2), add 100, and mod the result by 7. Python tells us that (2+100)%7=4 meaning 100 days from Tuesday in a Thursday. Try a few more examples. This example works well because our numeric code started at 0 for Sunday incremented by one each time until Saturday. The expression x%y will always return a number in the range 0 to y-1 inclusive. Suppose we shifted our numeric code by 3 spots yielding the following:
    3 Sunday
    4 Monday
    5 Tuesday
    6 Wednesday
    7 Thursday
    8 Friday
    9 Saturday
    
    Now (5+100)%7=0, so using mod directly on this code doesn't even give us a valid code number for a day of the week. This mod trick only works if the code starts at 0. Effectively we are computing how far we are away from the first day of the week (Sunday). Think about this example as you try to implement your cyclic cipher. If lowercase 'a' had a numeric code of 0, the problem would be much easier. The problem is ord('a') = 97. If you first determine how far you need to shift relative to 'a', you can still use the mod trick.
Submit

Once you are satisfied with your programs, hand them in by typing handin21 at the unix prompt. You may run handin21 as many times as you like, and only the most recent submission will be recorded. This is useful if you realize after handing in some programs that you'd like to make a few more changes to them.