Lab 11

Object-Oriented Design
Due at 6pm on Tuesday, December 5

The purpose of this lab is to:

• Practice designinng classes
• Learn to use an API to bring real-world data into a proogram

This lab refers to two example programs that you might want to download into your lab11 folder: DistanceExample.py and Tester.py

Getting Started

An Application Programming Interface (API) is a set of tools that allow an application program to make use of data or tools from a larger project. For example, if you look up the web page for a restaurant and it offers to give you directions to get there, you can be sure that the restaurant did not pay someone to write a direction-finding program. Google MAPS has a number of APIs, including one for finding directions and tools for including this service in a web page. In this lab we willl make use of a different Google API that finds distances between cities.

```
import urllib.request

def distance (start, dest):
# Gives the  distance in meters from
# start location to dest location
web_obj = urllib.request.urlopen(url)
web_obj.close()

D = eval(eval(results_str))
F = D["rows"][0]["elements"]
dist = F[0]["distance"]["value"]
return dist

def main():
d = distance( "Oberlin+OH", "New+York+NY")
print("Oberlin is %d meters from New York" % d )

main() ```

urllib is a standard Python module for working with web pages. The distance function uses one method of this module: urllib.request.urlopen( ), which takes a url that represents a query to a web page and returns a structure with the web page's response. In this case the web page is Google Map's distancematrix api, and the query is for the driving distance from the start city to the dest city. This is a simple request and the answer to it is just a number, but in general urllib.request.urlopen() needs to be able to handle very complex responses so it returns a complex structure. You don't need to know all of the details of how this works, but urllib.request.urlopen( ) returns a byte sequence (which means it is just a chunk of memory) that can be converted to a string that represents dictionary D. If you give D the key "rows" iit gives back a list, the first element of which is another dictionary. If you give that second dictionary the key "value" it gives the distance in meters between the two locations.

Note that the arguments to the distance function need to be strings with the format <city>+<state>, as in "Oberlin+Ohio", "Oberlin+OH", "New+York+NY". For Canadian cities you can use the province instead of a state: "Toronto+ON", "Montreal+QC". Some cities in Mexico might be listed "Mexico+City+Mexico" and "Oaxaca+Mexico". The API doesn't seem to extend to South America.

The Trip and RoundTrip classes

Your task in this lab is to implement a module Trips.py containing two classes: Trip, and its subclass RoundTrip. These classes have the same methods, but some of the methods work differently between the two classes.

Constructors: The Trip constructor takes any number of arguments (see below for notes on how to handle this), including possibly no arguments. The first argument, if there is one, is the source or starting location of the trip. The remaining arguments are destinations to visit. The trip this represents starts at the source and visits each of the destinations in order. For example,Trip("Oberlin+OH", "Washington+DC", "New+York+NY") represents a trip that starts in Oberlin, proceeds to Washington, and then travels to New York. The RoundTrip constructor is similar, only a Roundtrip returns to its source after the last destination.

Length( ): This returns the distance in miles for the complete Trip or RoundTrip. Remember that for RoundTrips this includes the distance from the final destination to the source.

Print( ): This prints a table listing each leg of the trip and the cumulative distance through that leg. For exampe, for the RoundTrip from Oberlin to Washington to New York to Boston to Buffalo this might print:

```         Oberlin+OH 0.00
Washington+DC 390.50
New+York+NY 615.41
Boston+MA  832.36
Buffalo+NY 1287.47
Oberlin+OH 1510.58
```
SetSource( city ): This installs the given city as the trip source, overwriting any previous source. The destinations are unaffected.

AddDestination (city):This adds the given city to the end of the list of destinations. For example, if a RoundTrip is currently from Oberlin to New York (and back to Oberlin) and we add Boston, then the new RoundTrip will proceed from Oberlin to New York to Boston (and back to Oberlin). This has no effect on the source of a trip.

InsertDestination( city, n ): This adds the given city to the list of destinations, inserting it at position n. The destinations are numbered starting with 1. If a Trip currently has k destinations the valid positions for an insert are 1,2,...,k+1. If the trip currently has k destinations inserting at position k+1 has the same effect as doing an AddDestination. If we have a current Trip from Oberlin to New York and add Washington at position 1 the Trip will then proceed from Oberlin to Washington and then to New York.

RemoveDestination(city): This removes every instance of the given city from the list of destinations. The source is unaffected, even if it happens to be the given city. If this city is not one of the destinations a message to that efffect should be printed.

GetSource( ): Returns the source city, or the empty string if there is none.

GetDestinations( ): Returns a list of the destination cities.

Handling variable numbers of arguments to a function:

If a function parameter is preceeded by the "*" character then the value of that parameter is a tuple that may contain any number of actual arguments. Starred parameters are generally the last of a function's parameters and all unattached arguments are assigned to the. For example, consider the function

```       def foo( a, *b):
print("a is: ", a)
print( "b is: ", b)
```
If we call this with foo(1,2,3,4,5) it prints
```     a is 1
b is (2,3,4,5)
```
On the other hand, if we call it with foo(34) it prints
```     a is 34
b is ( )
```
In the Trip and RoundTrip classes you should use a starred parameter for the list if cities. Of course, you can access the individual cities with a for-loop.

Your code for both classes should be contained in module Trips.py. Here is a sample application program Tester,py that tests some of the features of your classes:

```import Trips

def main():
t = Trips.Trip("Oberlin+OH", "Boston+MA")
t.Print()
print()
r = Trips.RoundTrip("Oberlin+OH", "Washington+DC", "New+York+NY", "Boston+MA" )
r.Print()

main()

```

You will want to extend this to test all of the methods you implement.

Handin

If you followed the Honor Code in this assignment, insert an HonorCode file attesting to this:.

I affirm that I have adhered to the Honor Code in this assignment.

You now just need to electronically handin all your files. As a reminder

```
% cd             # changes to your home directory
% cd cs150       # goes to your cs150 folder
% handin         # starts the handin program
# class is 150
# assignment is 11
# file/directory is lab11
% lshand         # should show that you've handed in something
```

You can also specify the options to handin from the command line

```
% cd ~/cs150     # goes to your cs150 folder
% handin -c 150 -a 11 lab11
```

File Checklist

You should have submitted the following files:
`   Trips.py   HonorCode`