CS0007 Assignment 3, Fall 2009
Smart Slideshows

NOTE

Check the schedule. A solution to part of the problem will be due midway to the final submission date.

Purpose

The purpose of this assignment is to give you practice using dictionaries, reading from text files, and designing larger pieces of code. In assignment 1, you wrote the bodies of small functions which had been planned out for you -- you were given their headers and docstrings. In assignment 2, you had a chance to design your own helper functions. For this assignment, you will design all of the functions. The assignment specifies only what the input and output should be for your program; all of the program design is up to you this time.

You and your partner should spend at least one hour reading through this handout to make sure you understand what is required. Be sure to get any clarification you need as soon as possible, and start working on the assignment, even in little bits, early.

Introduction

You probably use software like Apple's iPhoto or Windows Photo Gallery to keep track of your digital photographs. These programs allow you to create albums or slideshows from specific photos, based on things like your rating of the photo, when it was taken, or who is in it. For this assignment, you will write a program that allows the user to create a custom slideshow based on the faces, places and events depicted in their pictures.

Your program is designed to be run from a folder that contains a number of picture files, plus a special text file that contains information about those pictures. Your program will read this data, and then interact with the user to create the list of the photos they want to see. In a more realistic program, this interaction would involve a graphical user-interface with buttons and menus and so on. We're not quite ready for that yet, so we'll interact via typing.

Your Task

Your program should do the following:

The sections below describe these steps in detail.

Interaction with the user

Your program's correctness will be evaluated by another program, while other aspects that require more judgment will be assessed by a TA. In order for our program to know whether yours works properly or not, you must follow our specifications very carefully, and your input and output must match exactly with what we expect, both in content and format. To be sure that this is the case:

Input file format

The picture data file is a plain text file that contains names of picture files, such as "91238.jpg" and data about the contents of the pictures. You will find it easier to understand the formal definition of the file format below if you look at a sample picture data file at the same time.

A picture data file contains one or more sets of the following:

It is easy to imagine a "faces" section that would include multiple names, since pictures often include more than one person. With places and events, there will often be only one for each picture. However, you could imagine having more than one, for instance, where one is general and another is more specific. For example, you might say that an image is of the place "home" and also of "the back yard"; and you might say that a picture is of the event "Jane and Bruce's wedding" and also of "the speeches".

Building your data structures

In order to filter the picture list so that, for example, it includes only pictures with "William" but not "Catherine", and only from event "10th birthday", you need to store the information from the picture data file in some Python objects. (The alternative would be to re-read the picture data file constantly, but that is very inefficient; reading from files is slower than looking things up in objects). We call these Python objects "data structures".

Your program must create the following objects as it reads the picture data file:

In order to make filtering easier for the user, convert all strings from the faces, places, and events lists to lowercase before storing them in your dictionaries. (See below.)

Your program must consult these data structures, as appropriate, in order to filter the initial list of pictures according to the user's wishes. You may not create any additional objects to store the information from the picture data file.

The filtering process

You will find it easier to understand this description of the filtering process if you look at a sample interaction at the same time.

The user has the option of filtering the full list of image files down to a smaller set, based on the faces, places, and events that they want or don't want included. Here is how that process should work.

After reading the name of a face, place or event, convert it to all lowercase. That way, when you look for it in the dictionary (which has faces, places and events in all lowercase) matching will happen regardless of case. This makes it a little easier for the user.

In order to simplify your program, however, filtering will be based on exact string equality. Suppose the user wants to filter the list based on a face, they give the name "Catherine", and they want that face included. Then a picture stays in the picture list only if the exact string "catherine" was on the picture's face list. (Notice that the user's input has been converted to lowercase, as mentioned above.) It's not good enough if "cath" or "catherine fairgrieve" was on the picture's face list.

Printing the final list

Once filtering is complete, your program must print the pared down list of pictures (that is, the names of the picture files) to the shell. These must be printed with five names per line, separated by a semicolon and a blank. The final name should be followed by a semicolon.

The slideshow

The last thing your program must do is ask the user whether they want to see a slideshow of their pared down picture list. If they do, first ask them for how many seconds they would like to view each picture. Then display each picture, one at a time, for that many seconds. After each picture's display period is over, remove it from display by calling function media.close.

There is a simple way to let a period of time elapse in your program: import a module called time and call the function time.sleep, passing it a number of seconds.

Advice on how to design the program

This is your first program where you have the freedom (and responsibility) to design all of the functions yourself. A significant part of your grade will be for how well you do this. Of course, you could write the entire program as a very large if __name__ == "__main__" section. This would be a poor design, however. You should use functions to divide your program into meaningful pieces.

One reason for introducing a function is to avoid repeating code. If you find that you need to do the same series of steps more than once, you should define a function once and call it several times instead. This is not the only reason to define functions, however. Functions help to break code into manageable chunks. This will improve the readability of your code and is worth doing even if you only need to call the function once.

Each time you need a new function, take the time to design it. In other words,

But you don't need to write the function at this point; you can write your entire main program as if the function already exists. When you've finished writing your main program, you already have a list of well-defined functions to complete.

You don't have to follow the above process so strictly. You may recognize early on that you are definitely going to need a function for a certain task. You can go ahead and design, write, and test that function before you write the code that needs to use it.

Whatever order you develop the code in, it is extremely wise to test it in small pieces as you go. That way, you are building a big program out of smaller pieces that already work. This is much easier than completing a draft of the whole program and then sitting down to try to make it work. It also leaves you the option of earning some part-marks for correctness if you run out of time before getting the whole program working, because you will at least have some of the functions working.

One extremely good (and disciplined) habit is to design your test cases for each function before you write the function. All you need is the function header and docstring in order to plan your testing. The process of planning it will force to to refine your thinking about how the function should perform in all possible situations. Update your docstring to reflect these refinements, and you will be in a really strong position to write a function that works, as well as code that gets what it expects when it calls your function.

Hint: There will be places in your program where you could end up repeating the same code 3 times, once for each dictionary. Avoid this by making a function that can do the task for any given dictionary.

Grading

These are the aspects of your work that we will focus on in the grading:

Sample Pictures

Some Sample pictures which are described by this photo data file are available in this directory.

What to Hand In

Hand in the file filter.py, which should contain your main program and all helper functions that you have written. Make sure that your program has an if __name__ == "__main__" section, and includes any import statements that are needed. It is a good idea to run your program one last time before submitting; sometimes students make a mistake during last-minute improvements and submit a program that doesn't run at all.

Remember that spelling of filenames, including case, counts: your file must be named exactly as above.