Lab Assignment 2

This assignment is due by 10:00 p.m. on Friday, October 13.

Preparation (Do this part individually, before coming to lab)

(1) If you're just getting enrolled in the class, do everything on the course refrence sheet (the syllabus) under the heading "What to do this week to get started in ICS 31." This includes registering yourself at piazza.com and filling out the questionnaire at eee.uci.edu/survey/ics31.f17.q.

(2) Read sections 2.3–2.5 of the Perkovic text, trying the practice problems (before looking at the solutions).

[Reading note: At the beginning of section 2.3, the list of pet names is homogeneous—all the items are of the same type, strings. Next, the author shows you a heterogenous list—one with items of various types. In our class, we will use lists only for homogeneous data (so, for example, we can apply the same operation to every item on a list); for heterogeneous collections of data, we will use namedtuples (as discussed in class).]

Read this brief introduction to namedtuples.

Why have a fractions module when we could just use float numbers? The book mentions situations where you have very large or very small numbers but need to calculate precisely. A related situation occurs when you need to calculate with values like 1/3 that cannot be represented precisely as a decimal number. In a long chain of computations, the difference between 0.33333333 and 1/3 can build up into a significant value; that's called a roundoff error. If you use the fraction library for those computations and convert to a float only at the very end, you avoid the potential for roundoff errors.

(3) Read sections 3.3 and 3.5 of the Perkovic textbook. (You can skip the section in the middle of page 71; it's more confusing than helpful.) We'll get to the other sections soon and if you have some time, you can go ahead and read the chapter in order. But we're going to be talking about these two sections first. As you read, do practice problems 3.8, 3.9, 3.13 (for the average function), and 3.16.

(4) The text uses the term "user-defined functions." A more modern, more accurate term would be "programmer-defined functions." Decades ago, a computer user was a person who wrote software, but today a user is an "end user" who rarely if ever writes any code.

(5) Functions might be the single most important concept in first-quarter programming. They're not the only important concept—we need a lot of concepts to write useful programs—but encapsulating operations into a named function and then using that function as a component of still larger functions, that's a basis of all software development. Functions are also sometimes called procedures, methods, subroutines, or subprograms; sometimes those terms are used in subtly different ways, but sometimes not.

(6) Go back and read the assignment advice again, especially about the "three-minute rule."

(7) Read through the Lab Work part of this assignment before you come to lab on Monday, just to get an idea of what you'll be doing with your partner.


Lab Work (Do this part with your partner in lab)

(a) Choose a partner for this assignment, using the ICS Partner App. Remember that you'll choose a different partner for each lab assignment, so you'll work with this partner only this week. Your partner must be enrolled in the same lab section you're enrolled in. Make sure you know your partner's name (first and last) and contact information (Email or cellphone or whatever) in case one of you can't make it to lab.

(b) For this assignment, you will create a Python file called lab2.py. Type your answers to all the parts of this assignment into this file; non-Python text can be in comments or multi-line (triple-quoted) strings.

On the first line of the file type a comment with the names and IDs of both partners and some other identifying information, like this:

#  Paula Programmer 11223344 and Andrew Anteater 44332211.  ICS 31 Lab sec 7.  Lab Assignment 2.

All the Python code in your file should produce the specified results when you run the file. When you've finished the assignment, you'll submit this file via Checkmate. (It's a good idea if each partner keeps a copy of the lab work at the end of each session, just in case someone can't make it to the next lab.)

(c) In class we have written Python code similar to this:

print('How many hours?')
hours = float(input())
print('This many hours:', hours)
print('How many dollars per hour?')
rate = float(input())
print('This many dollars per hour:  ', rate)
print('Weekly salary:  ', hours * rate)

(c.1) Copy this code and paste it into your lab2.py file; then run it to make sure it works as you expect.

Then modify the code as shown below to reflect the alternate form of the input() function (with the "input prompt" string as an argument to the function). Run it, of course. Do you see the difference (i) in how it behaves and (ii) in how you write the code? Sometimes we prefer this alternative, sometimes we prefer the other, depending mostly on how we want our program to behave; neither one is the best in every case.

hours = int(input('How many hours?'))
print('This many hours:', hours)
rate = float(input('How many dollars per hour?'))
print('This many dollars per hour:  ', rate)
print('Weekly salary:  ', hours * rate)

Then modify the code to print a dollar sign before each dollar amount. (For now, don't worry about the precise spacing or the precise number of digits after the decimal point; we'll learn how to specify those later.)

(c.2) Write a new sequence of statements that, when executed, might produce results that look like this (where the bold-faced text would by typed by the user):

Hello.  What is your name?  Alice Anteater
Hello, Alice Anteater
It's nice to meet you.  
How old are you?  19
Next year you will be 20 years old.

The foregoing may be enough to get you going on this problem. But here are a couple of tips and bits of advice that may help give you a boost:

(d) The Copenhagen Chamber of Commerce has hired you to write a program that will convert foreign currencies to the equivalent amount in Danish krone. Your program will prompt the user to input four items, in this order: The name of the business using the program, the number of Euros that business has, the number of British pounds, and the number of U.S. dollars.

Your program will produce as output the business name, a list of how much of each currency the business has (in both the foreign amount and the Danish krone equivalent) with one foreign currency per line, and the business's total amount of money in krone.

Assume that the following exchange rates are in effect: One Euro is 7.46 krone, one British pound is 8.60 krone, one U.S. dollar is 6.62 krone. [Implementation note: This is one of those situations where hard-coding constants is appropriate, since our program is not going to look up the actual exchange rates on the internet. (That may be something you'll do in ICS 32, though.) At the top of your Python code you should have three assignment statements that define these constants; they should look like this: KRONE_PER_EURO = 7.46 . Then you will use those defined constants where appropriate in your program's calculations.]

For example, if the business name is Tycho Brahe Enterprises and it has €100, £200, and $1000, the displayed results would be as shown below (with the user's input shown in boldface):

Please provide this information:
Business name:  Tycho Brahe Enterprises
Number of euros:  100
Number of pounds:  200
Number of dollars:  1000

Copenhagen Chamber of Commerce
Business name:   Tycho Brahe Enterprises
100 euros is 746.0 krone
200 pounds is 1720.0 krone
1000 dollars is 6620.0 krone

Total krone:   9086.0

(Don't worry about the precise spacing or number of digits after the decimal point; we'll learn how to control that later on.)

(e) Start with this code (which you may copy and paste into your file to work with):

from collections import namedtuple
Book = namedtuple('Book', 'title author year price')
favorite = Book('Adventures of Sherlock Holmes',
                'Arthur Conan Doyle', 1892, 21.50)
another = Book('Memoirs of Sherlock Holmes', 
               'Arthur Conan Doyle', 1894, 23.50)
still_another = Book('Return of Sherlock Holmes',
                     'Arthur Conan Doyle', 1905, 25.00)

Write expressions using the variables favorite, another, and still_another that evaluate to each of the following; then print (the value of) each expression:

(e.1) the title of the book in the variable still_another .

(e.2) the price of the book Memoirs of Sherlock Holmes

(e.3) the average price of all three books

(e.4) True or false, based on whether the publication year of the book in the variable favorite is before 1900.

Next, write two assignment statements [until next week's class, the way to do this is to create a new Book object based on the old one (except for the field you're changing)]:

(e.5) Change the price of the book Return of Sherlock Holmes to $26.00

(e.6) Change the price of the book Return of Sherlock Holmes by increasing it 20% (over whatever its current price is)

(f) Define a namedtuple called Animal for animals in a zoo, with fields for the animal's name, its species, its age, its weight, and its favorite food.

Then define variables to hold (i) an elephant called Jumbo that's 50 years old, weighs 1000 kg, and eats peanuts, and (ii) a platypus named Perry that's 7 years old, weighs 1.7 kg, and eats shrimp.

Finally, write a boolean expression whose value is true if the weight of the animal represented by the first variable is less than the weight of the animal represented by the second variable.

You might be asking yourself why it's useful to write an expression like that when we know from looking at the data that Jumbo weighs more than Perry. The answer is that variables can vary; that is, we might have a program where different animals, or different weights for the same animals, get stored in the variables you defined. Because the expression you wrote uses whatever value the variable currently has, we can re-use that same expression for whatever animals we want, so long as we store those animals' information in the variables you defined and used in your expression. It's good to write general, versatile code like this.

(g) Add this statement to your book code:

booklist = [favorite, another, still_another]

(g.1) Write a boolean expression whose value is true if the first book on the list [remember what the index number of the first book is] is cheaper than the second book on the list (and false otherwise). (In your lab2.py file, just print this expression.)

(g.2) Write (and print) another boolean expression whose value is true if the first book on the list is more recently published than the last book on the list. Don't write this using booklist[2] for the last book; instead, use an expression whose value would be the last book on the list, no matter how long the list is.

(h) In class we discussed how a programming language gives us predefined or built-in "building blocks" (like ints and strings, and like + and len()) and then gives us ways to combine them into more complicated and powerful features that we can use as we develop our software. Namedtuples are an example of this; after we create a Book, our version of Python has a new type of data we can use in our programs.

One theme of this course is how we can build and work with data structures in this way.

Here we create a list of seven restaurants, calling it RC (for "restaurant collection"). Copy this code into your lab2.py file.

from collections import namedtuple     # If this line is in your file already, you don't need it again
Restaurant = namedtuple('Restaurant', 'name cuisine phone dish price')
# Restaurant attributes: name, kind of food served, phone number, best dish, price of that dish
RC = [
    Restaurant("Thai Dishes", "Thai", "334-4433", "Mee Krob", 12.50),
    Restaurant("Nobu", "Japanese", "335-4433", "Natto Temaki", 5.50),
    Restaurant("Nonna", "Italian", "355-4433", "Stracotto", 25.50),
    Restaurant("Jitlada", "Thai", "324-4433", "Paht Woon Sen", 15.50),
    Restaurant("Nola", "New Orleans", "336-4433", "Jambalaya", 5.50),
    Restaurant("Noma", "Modern Danish", "337-4433", "Birch Sap", 35.50),
    Restaurant("Addis Ababa", "Ethiopian", "337-4453", "Yesiga Tibs", 10.50) ]

For each of the values described below, write a Python expression using RC that produces that value (and enclose it in a print statement in your lab2.py file). [Treat each problem separately, assuming only that you have the definitions above and not the results of the previous problems here in part (h).]

(h.1) The name of the third restaurant on the list (remember that the third restaurant is not number 3)

(h.2) True or False, whether the first and the fourth restaurants serve the same kind of food

(h.3) The price of (the best dish at) the last restaurant on the list (write this one so that it works for lists of any length, not just 7)

(h.4) The list of restaurants, arranged alphabetically by restaurant name (you'll need one statement before the print statement; this involves the sort() method for lists).

(h.5) The best dish at the restaurant whose name is alphabetically last; in other words, the dish field of the last restaurant in the list of restaurants sorted alphabetically by name (you'll need an extra statement here, too; your solution should work for lists of any length).

(h.6) A new list containing 4 restaurants: the first two alphabetically and the last two alphabetically (this one should work for lists of any length; you may need a couple of extra statements and the sort() or the extend() method [see help(list)])

(h.7) Take a moment before going on to the next problem. Look at the six previous parts of this problem and see how, taken together, solving them has given you practice with indexing, Boolean expressions, sort(), and combining these techniques.

Most of the multi-part problems on the lab assignments are variations on a theme, building to a conclusion that combines techniques or solves a larger problem. As you complete each problem, look back to see how the parts fit together and what the theme might be or how the parts build to the conclusion. Stronger students do this kind of examination and analysis; weaker students just stop when they've written down the answers.

(i) Python exercises:

Python comes with a library called tkinter that enables drawing and other image processing. (It also supports graphical user interfaces (GUIs)—meaning code that displays menus and buttons and responds to mouse actions—but that's a topic for ICS 32.)

Here is the code to create a window and draw an "X":

import tkinter              # Load the library; do this just once per program

my_window = tkinter.Tk()    # Create the graphics window

my_canvas = tkinter.Canvas(my_window, width=500, height=500)  # Create a 500x500 canvas to draw on
my_canvas.pack()            # Put the canvas into the window

my_canvas.create_line(100, 100, 300, 300, fill='orange') # Draw orange line
my_canvas.create_line(300, 100, 100, 300, fill='blue')   # Draw blue line

tkinter.mainloop()          # Combine all the elements and display the window

Copy this code into a fresh Python file and run it to make sure it works on your system. You should get a separate window whose title is "tk", containing an "X" with one orange line and one blue line. When you're done admiring it, close the window to terminate your program.

If you have a lot of other windows open on your screen, the graphics window may be hidden; close windows or move them around until the graphics window is visible. If you run into other problems and don't get a window with an "X" as described, you'll need to see someone to get some help. There's no point going on until you can make this code work.

The tkinter library has many more capabilities than we will be able to cover this quarter. We're using it because it gives us examples of imperative (step-by-step) programming and because graphical examples are fun. The point is to learn the programming concepts rather than memorize the details of tkinter. On quizzes and exams, if the problems involve tkinter at all, you can expect us to give you a brief reference summary for most of the tkinter details you'll need.

In solving the exercises that follow, you will leave all the lines in the example program above untouched, except for the two "Draw" lines; you will replace those lines with the solution to each exercise.

If you've been reading this code and trying to follow what it does, you may have guessed that the numbers that are arguments to the create_line method are the coordinates for points on the screen, but they may have seemed oddly unlike the cartesian coordinates we're used to, with (0,0) in the center. Coordinates in computer graphics are different: The origin, point (0,0), is the upper left corner; x-values extend positively to the right and y-values extend positively down. So the orange line in our code above starts at (100,100)—100 pixels to the right of the top left corner and 100 pixels down—and extends to (300,300).

To draw on our canvas, we call methods for creating lines, circles, and other shapes. The form (syntax) of these method calls is:

my_canvas.method name ( list of arguments )

That is, the name of the canvas object (we'll always just use my_canvas in these problems), a dot, the name of the method, and then a parenthesized list with all the arguments (inputs to the method) listed in the correct order, separated by commas.

The arguments to create_line, as illustrated above, are

Arguments to some methods in Python, like the color above, are called "keyword arguments"; they have the argument's name (in this case fill= followed by its value).

The tkinter library provides these methods for drawing a variety of objects:

 |  create_arc( )
 |      Create arc shaped region with coordinates x1,y1,x2,y2.
 |  create_line( )
 |      Create line with coordinates x1,y1,...,xn,yn.
 |  create_oval( )
 |      Create oval with coordinates x1,y1,x2,y2.
 |  create_polygon( )
 |      Create polygon with coordinates x1,y1,...,xn,yn.
 |  create_rectangle( )
 |      Create rectangle with coordinates x1,y1,x2,y2.
 |  create_text( )
 |      Create text with coordinates x1,y1.

The list above is excerpted from what you'd get by typing help(tkinter.Canvas) in the Python Shell. There is more information on the web and at www.python.org, but all this documentation has far more detail than we'll ever need this quarter. You can answer all the exercises below with just the information provided in this assignment.

(i.1) Using tkinter, draw a series of lines on a canvas that form a square with sides 200 pixels long.

(i.2) As you did in the previous exercise, draw a diamond that would fit exactly inside a square with sides 200 pixels long.

(i.3) Draw a simple front-view picture of a house (with a roof, walls, at least one window, and a door).

(i.4) Draw a picture of an eye (with a pupil and an iris, at least). The method create_oval can draw circles:

my_canvas.create_oval( top left x value, top left y value, bottom right x value, bottom right y value, fill = color)

The upper right and lower left points describe a rectangle; the oval it draws is "inscribed" in that rectangle. If the rectangle is a square, the oval is a circle.

(i.5) (optional, but see (i.6) below) Choose one of the following:

(i.6) Copy all your code from part (i) to the end of your lab2.py file and run it again to make sure it all works.

(j) Remember that each partner must complete a partner evaluation form and submit it individually, using the partner app. Make sure you know your partner's name, first and last, so you can evaluate the right person. Please complete your evaluation by the end of the day on Friday, or Saturday morning at the latest. It only takes a couple of minutes and not doing it hurts your participation score.

What to turn in: One member of each pair (not both) must submit via Checkmate the single lab2.py file with your solutions to parts (c) through (i). Make sure both partners' names appear at the top of the file. It would be an excellent idea to go back and re-read those parts carefully now, to make sure you've completed all the steps specified. It would also be an excellent idea to run your file one last time to make sure all the correct results appear, with no error messages. (If you run into problems, it's probably because you have more than one function with the same name. Change one of the names [everywhere necessary] and try to Run again.)

Also remember that each student must complete a partner evaluation form using the partner app. We won't be sending Email reminders; it's up to you to do this each week. These evaluations contribute to your class participation score. It should only take a minute or two, so get in the habit of doing this every week on Friday after you've submitted your assignment; the partner evaluations close on Saturday morning. (Note, by the way, that the partner app will let you resubmit a revised evaluation, should you think of something more to add, so long as it's still before the Saturday morning cutoff.)


Written by David G. Kay in Fall 2012 for ICS 31. Modified by David G. Kay, Winter 2013, Fall 2013, Winter 2014, Fall 2014, Winter 2015, Fall 2015, Winter 2016, Fall 2016, Spring 2017. Python exercises by David Lepe, edited by David G. Kay.

David G. Kay, kay@uci.edu
Thursday, October 19, 2017 2:38 PM