Difference between revisions of "CSC111 Homework 11 2015"

From dftwiki3
Jump to: navigation, search
 
(18 intermediate revisions by the same user not shown)
Line 6: Line 6:
  
 
<bluebox>
 
<bluebox>
This Homework is due on 4/21/15 at 11:55 p.m.
+
This Homework is due on Tuesday evening, 4/21/15, at 11:55 p.m.
 
</bluebox>
 
</bluebox>
  
Line 16: Line 16:
 
* Your assignment is to write a program that reads weather data from a text file, then processes the data, and finally outputs the answers to several questions.
 
* Your assignment is to write a program that reads weather data from a text file, then processes the data, and finally outputs the answers to several questions.
  
* Call your program '''hw11.py'''
+
* Call your program '''hw11_1.py'''
  
==The Text File==
+
==The Weather Data Files ==
The Web site http://www.metoffice.gov.uk/climate/uk/stationdata/ keeps records of temperatures for '''37''' towns/cities of the UK for the past few years, going back in some cases to 1853.
+
<br />
 
+
* The British government has been keeping track of temperatures in several cities of the U.K.  The official Web site where the data is available is http://www.metoffice.gov.uk/climate/uk/stationdata/.  The records of temperatures for '''37''' towns/cities of the UK for the past few years, going back in some cases to 1853, are kept on this site.
Your assignment deals with data taken from this site.  The different lists of temperatures have been stored on a local server at Smith College, and several are given to you to test your program on.
+
<br />
 
+
* The data recorded consists of these quantities
==Background Information==
+
:* Mean daily maximum temperature (tmax)
 
+
:* Mean daily minimum temperature (tmin)
* The main address for the data is that of the Met-Office site:  http://www.metoffice.gov.uk/climate/uk/stationdata/ 
+
:* Days of air frost (af)
 
+
:* Total rainfall (rain)
* The data has been replicated at http://cs.smith.edu/~dthiebaut/UKTemperatures/, and you can use this Smith-based Url instead. The data files are the same at both places.
+
:* Total sunshine duration (sun)
 
+
:(More information can be found [[media:www_metoffice_gov_uk.pdf| here]].)
* A file name is associated with each city or town.  For example, the city of '''Aberporth''' is associated with '''aberporthdata.txt''', and the record of the weather data for '''Aberporth''' is stored at URL http://cs.smith.edu/~dthiebaut/UKTemperatures/aberporthdata.txt
+
<br />
 
+
* The format for the data is CSV.
* The name of the file is simply the name of the town, all lowercase, followed by "data.txt."
+
* The data from the UK Web site have been mirrored on a Smith server: [http://cs.smith.edu/~dthiebaut/UKTemperatures/  http://cs.smith.edu/~dthiebaut/UKTemperatures/].  You will need to download a few files from that site to develop and test your program.
 +
* The name of a file is simply the name of the U.K. town, all lowercase, suffixed by "data.txt."
  
 
<br />
 
<br />
 
===Format of the data===
 
===Format of the data===
 
<br />
 
<br />
* The format of the data is explained at http://www.metoffice.gov.uk/climate/uk/stationdata/, a copy of which is available [[media:www_metoffice_gov_uk.pdf| here]].
+
* Instead of relying on the weather site in the U.K., we have mirrored the data files on a Smith server.
 
+
* Download one of the files from  [http://cs.smith.edu/~dthiebaut/UKTemperatures/ http://cs.smith.edu/~dthiebaut/UKTemperatures/], say '''armaghdata.txt''', and take a look at it. Use '''Notepad''', '''TextEdit''' or your favorite text editor to open the file.
* Your program should accept ''estimated'' data as well as ''real data''. In other words, data followed by an asterisk should not be dropped or skipped by your program.
+
* You will notice that when measurements are missing, they are replaced by "---".  Your program should not skip measurements that are missing.
 +
* Sometimes, especially at the end of the file, measurements are suffixed with an asterisk (*).    Your program should discard the asterisk, and treat the data as valid.
 +
* Some lines have the word "Provisional" at the end.  Your program should treat these lines the same as regular line, and should '''not''' skip them.
 
<br />
 
<br />
 
===Input===
 
===Input===
 
<br />
 
<br />
Your program should prompt the user for a file name.  The user will supply the name of one of the text files that will have been previously downloaded from the Smith Web site listed above.  In other words, your program simply needs to read a text file and does not need to access the Web.
+
* Your program should prompt the user for a file name.  The user will supply the name of one of the text files '''that will have been previously downloaded from the Smith Web site'''.  In other words, your program simply needs to read a text file and does not need to access the Web.  
 +
* If the user provides an invalid file name, your program will keep on prompting the user for a new name.  Your program will only start processing the data once it has been given a valid file name.
 +
 
 
<br />
 
<br />
 
===Processing===
 
===Processing===
 
<br />
 
<br />
* You must use the method illustrated in the first 2 problems of [[CSC111 lab 11 2015|Lab 11]] to process the data.  
+
* You must use the method illustrated in the Animals and Presidents problems of [[CSC111 Lab 11 2015|Lab 11]] to process the data.  
* All temperatures should be reported in degrees '''Celsius''' which is the system used in the U.K.
+
* All temperatures should be reported in degrees '''Celsius''' which is the system used in the U.K. (so you do not need to transform the temperatures).
 
<br />
 
<br />
 
==Questions==
 
==Questions==
 
<br />
 
<br />
 
;Question 1
 
;Question 1
:  In what year or years was the coldest temperature recorded?  If the coldest temperature appears several times, list all the years and month in which it will have been reported.  
+
:  In what year or years was the coldest temperature recorded?  If the coldest temperature appears several times, list all the years and month in which it will have been reported.  The format of the output is illustrated in a later section.
 
<br />
 
<br />
 
;Question 2
 
;Question 2
  
:  In what year or years was the warmest temperature recorded?  If the warmest temperature appears several times, list all the years and month in which it will have been reported.  
+
:  In what year or years was the warmest temperature recorded?  If the warmest temperature appears several times, list all the years and month in which it will have been reported.  The format of the output is illustrated in a later section.
  
 
;Question 3
 
;Question 3
: What are the 5 sunniest months and years for the given city?
+
: What are the 5 sunniest months and years for the given city?   The format of the output is illustrated below.
 
<br />
 
<br />
 
==Output Format==
 
==Output Format==
Line 69: Line 74:
 
  Invalid file name, please re-enter
 
  Invalid file name, please re-enter
 
  > armaghdata.txt
 
  > armaghdata.txt
  1 -4.2 1878 12 1895 2  
+
  1, -4.2, 1878, 12, 1895, 2
  2 23.8 1995 8 1989 7  
+
  2, 23.8, 1995, 8, 1989, 7
  3 (256.0C) 1940 6 (252.9C) 1949 6 (251.6C) 1935 5 (244.1C) 1957 6 (243.8C) 1989 7  
+
  3, 256.0, 1940, 6, 252.9, 1949, 6, 251.6, 1935, 5, 244.1, 1957, 6, 243.8, 1989, 7
 
   
 
   
 
<br />
 
<br />
Line 77: Line 82:
 
   
 
   
 
  > ballypatrickdata.txt
 
  > ballypatrickdata.txt
  1 -1.8 1979 1  
+
  1, -1.8, 1979, 1
  2 20.0 1995 8  
+
  2, 20.0, 1995, 8
  3 (279.3C) 1975 5 (272.6C) 1976 8 (253.7C) 1977 5 (247.2C) 1984 5 (245.6C) 1974 4  
+
  3, 279.3, 1975, 5, 272.6, 1976, 8, 253.7, 1977, 5, 247.2, 1984, 5, 245.6, 1974, 4
 
   
 
   
 
:Note that each line is prefixed with a number, identifying the question for which the line is the answer.
 
:Note that each line is prefixed with a number, identifying the question for which the line is the answer.
   
+
: The order in which the years of min or max temperature are listed is unimportant.
 +
: All the floating point numbers are printed with 1 decimal after the point.
 +
: The sunniest months are listed in order of decreasing exposure.
 +
 
 +
:Note, also, that the output is in CSV form. A coma separates all the values.  No extra spaces should appear in front of comas.
 +
 
 
==Moodle Submission==
 
==Moodle Submission==
  
* Submit your program in the Moodle HW11 PB1 section.
+
* Submit your program in the Moodle HW11 PB1 section.   You will not be allowed to evaluate this program, so make sure you test it thoroughly.
 +
<br />
 +
<br />
 +
=Problem 2: Class Inheritance=
 +
<br />
 +
==Preparation==
 +
<br />
 +
* Create a file called '''car.py''', containing the following code:
 +
<br />
 +
::<source lang="python">
 +
# car.py
 +
# CSC111
 +
# This file contains the definition of a Wheel and a Car
 +
# The car is a convertible, with a rectangular body,
 +
# a windshield, and two wheels.
 +
from graphics import *
 +
 
 +
#----------------------------------------------------------------
 +
class Wheel:
 +
    """A class with two concentric circles"""
 +
 
 +
    def __init__( self, center, r1, r2 ):
 +
        self.circ1 = Circle( center, r1 )
 +
        self.circ2 = Circle( center, r2 )
 +
        r1, r2 = min( r1, r2 ), max( r1, r2 )
 +
        self.radius1 = r1
 +
        self.radius2 = r2
 +
       
 +
    def draw( self, win ):
 +
        self.circ2.draw( win )
 +
        self.circ1.draw( win )
 +
 
 +
    def setFill( self, color1, color2 ):
 +
        self.circ1.setFill( color1 )
 +
        self.circ2.setFill( color2 )
 +
 
 +
    def getRadius1( self ):
 +
        return self.radius1
 +
 
 +
    def getRadius2( self ):
 +
        return self.radius2
 +
 
 +
    def move( self, dx, dy ):
 +
        self.circ1.move( dx, dy )
 +
        self.circ2.move( dx, dy )
 +
 
 +
#----------------------------------------------------------------
 +
class Car:
 +
    """a class containing a rectangle and 2 wheels"""
 +
 
 +
    def __init__( self, P1, P2 ):
 +
        """constructs the car.  The top-left and bottom-right points
 +
        defining the body of the car are given."""
 +
        #self.P1 = P1
 +
        #self.P2 = P2
 +
        self.width = abs( P1.getX()-P2.getX() )
 +
        self.height= abs( P1.getY()-P2.getY() )
 +
       
 +
        #--- define rectangle---
 +
        self.body    = Rectangle( P1, P2 )
 +
 
 +
        #--- add a triangle for windshield ---
 +
        P3 = Point( P1.getX()+self.width//5, P1.getY() )
 +
        P4 = Point( P1.getX()+self.width//3, P1.getY() )
 +
        P5 = Point( P4.getX(), P1.getY()-self.height//2 )
 +
        self.windshield = Polygon( P3, P4, P5 )
 +
        self.windshield.setFill( "lightblue" )
 +
       
 +
        #--- and the two wheels ---
 +
        center1      = Point( P1.getX()+self.width/8, P2.getY() )
 +
        center2      = Point( P1.getX()+self.width*7/8, P2.getY() )
 +
        radius2      = self.height/3
 +
        radius1      = radius2/2
 +
        self.wheel1  = Wheel( center1, radius1, radius2 )
 +
        self.wheel2  = Wheel( center2, radius1, radius2 )
 +
 
 +
    def draw( self, win ):
 +
        """draw rectangle  2 wheels on window"""
 +
        self.body.draw( win )
 +
        self.windshield.draw( win )
 +
        self.wheel1.draw( win )
 +
        self.wheel2.draw( win )
 +
 
 +
    def setFill( self, color1, color2, color3 ):
 +
        """defines the color of the car.  First is body, then inside wheel, then tire color"""
 +
        self.body.setFill( color1 )
 +
        self.wheel1.setFill( color2, color3 )
 +
        self.wheel2.setFill( color2, color3 )
 +
 
 +
    def move( self, dx, dy ):
 +
        """defines direction of movement for all 3 elements of car"""
 +
        self.body.move( dx, dy )
 +
        self.windshield.move( dx, dy )
 +
        self.wheel1.move( dx, dy )
 +
        self.wheel2.move( dx, dy )
 +
     
 +
</source>
 +
<br />
 +
* Create a new program called '''hw11_2.py''' with the code below:
 +
<br />
 +
::<source lang="python">
 +
 
 +
 
 +
# hw11_2.py
 +
# your name here
 +
#
 +
# This program draws a car on the graphics window
 +
# and moves it a few pixels.
 +
from graphics import * # import all the graphic elements (Rectangles, etc.)
 +
from car import *        # import the Wheel and Car classes from car.py
 +
WIDTH = 600
 +
HEIGHT= 600
 +
       
 +
def main():
 +
    global W, H
 +
    win = GraphWin( "Put your name here", WIDTH, HEIGHT )
 +
 
 +
    # create a car
 +
    car = Car( Point( 100,100 ), Point( 250, 170 ) )
 +
 
 +
    # set the color of its different parts and draw it
 +
    car.setFill( "red", "yellow", "black" )
 +
    car.draw( win )
 +
   
 +
    # move it
 +
    for i in range( 100 ):
 +
        car.move( -2, 0 )
 +
       
 +
    win.getMouse()
 +
   
 +
if __name__=="__main__":
 +
    main()
 +
</source>
 +
<br />
 +
==Assignment==
 +
<br />
 +
Your assignment is to create two new classes '''inside''' the hw11_2.py program.  The first class will be called Truck, and is derived from Car.  The second class is called SuperTruck, and is derived from Truck.
 +
<br />
 +
===Truck Class===
 +
[[Image: TruckDerivedFromCar.png|right|150px]]
 +
<br />
 +
* The Truck must be derived from the Car class.
 +
* The constructor for the Truck is given two points and three colors.  Creating a truck, drawing it, and moving it a few pixels is illustrated below.  The corresponding truck is shown on the right hand side.
 +
<br />
 +
::<source lang="python">
 +
 
 +
    truck = Truck( Point( 300, 200 ), Point( 400, 250 ), "red", "grey", "blue" )
 +
    truck.draw( win )
 +
    for i in range( 20 ):
 +
        truck.move( -2, 0 )
 +
 
 +
</source>
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
===SuperTruck Class===
 +
[[Image: SuperTruckDerivedFromTruck.png|right|150px]]
 +
<br />
 +
* The SuperTruck must be derived from the Truck class.
 +
* Creating a SuperTruck object, drawing it, and moving it a few pixels to the left is illustrated below.  The corresponding image is shown to the right.  A SuperTruck object is constructed by giving it a reference point, which is the top-left point of the rectangle forming the body of the truck, a width, and a height for the body of the truck, and the color of the body and top of the super truck.
 +
The top of the SuperTruck extends from the windshield to the end of the body.
 +
<br />
 +
::<source lang="python">
 +
 
 +
    sTruck = SuperTruck( Point( 450, 300 ), 100, 75, "yellow" )
 +
    sTruck.draw( win )   
 +
    for i in range( 20 ):
 +
        sTruck.move( -2, 0 )
 +
 
 +
</source>
 +
<br />
 +
<br />
 +
<br /><br />
 +
<br />
 +
==Submission==
 +
<br />
 +
* Submit a copy of the graphics window showing a car, a truck and a super-truck.  Look for the HW11 PB2 Image section on Moodle. Assuming that we use the code above to create them, the image created by your program should be as close to the one below as possible (except for the text in grey, of course):
 +
<br />
 +
<center>
 +
[[Image:CarTruckSuperTruck.png|500px]]
 +
</center>
 +
* Submit a copy of your program '''hw11_2.py''' in the HW11 PB2 section on Moodle.
 +
</showafterdate>
 +
<br />
 +
<br />
 +
<!-- ================================================================== -->
 +
<showafterdate after="20150422 00:00" before="20150601 00:00">
 +
=Solution Programs=
 +
<br />
 +
==Problem 1==
 +
<br />
 +
<source lang="python">
 +
# hw11_1.py
 +
# D. Thiebaut
 +
# This program prompts the user for a file name that contains data about
 +
# weather conditions recording a given month in a British city.  The source
 +
# of the data is taken from http://www.metoffice.gov.uk/climate/uk/stationdata/
 +
# This program outputs several quantities, including the years and months when
 +
# the coldest temperature was recorded, the year the warmest temperature was recorded,
 +
# the 5 sunniest months and years.
 +
 
 +
def getData():
 +
    #return open( "armagh.txt", "r" ).read()
 +
 
 +
    fileName = input( "> " )
 +
    while True:
 +
        try:
 +
            text = open( fileName, "r" ).read()
 +
            return text
 +
        except:
 +
            print( "Invalid file name.  Reenter" )
 +
        fileName = input( "> " )
 +
 
 +
def main():
 +
    text = getData()
 +
    lines = text.split( "\n" )
 +
 
 +
    # create a list of just year, month, minT, maxT, rain, and sun
 +
    list = []
 +
    for line in lines:
 +
        line = line.strip()
 +
        if len( line ) == 0:
 +
            continue
 +
 
 +
        # skip line that do not start with a year
 +
        if not line[0] in ['1', '2']:
 +
            continue
 +
 
 +
        # remove stars and "Provisional" and split
 +
        fields = line.replace( '*', '' ).replace( 'Provisional', '' ).split( )
 +
 
 +
        # split line into variables
 +
        if len( fields ) == 7:
 +
            year, month, maxT, minT, af, rain, sun = fields
 +
        else:
 +
            continue
 +
 
 +
        # create tuple and record it in list
 +
        tuple = ( year, month, maxT, minT, rain, sun )
 +
        list.append( tuple )
 +
 
 +
    #===============================================================
 +
    # Find coldest months and years on record
 +
    #===============================================================
 +
    # create a new list, putting min temperature first
 +
    listMinTemp = []
 +
    for year, month, maxT, minT, rain, sun in list:
 +
        if minT=="---":
 +
            continue
 +
   
 +
        listMinTemp.append( ( float(minT), year, month ) )
 +
 
 +
    # sort from coldest to warmest min temp
 +
    listMinTemp.sort()
 +
 
 +
    # find coldest temperature
 +
    coldest = listMinTemp[0][0]
 +
 
 +
    # find all months and years with that coldest temperature
 +
    print( "1, ", coldest, end="", sep="" )
 +
    for minT, year, month in listMinTemp:
 +
        if minT == coldest:
 +
            print( ", ", year, ", ",  month,  end="", sep="" )
 +
    print()
 +
 
 +
    #===============================================================
 +
    # Find warmest months and years on record
 +
    #===============================================================
 +
    # create a new list, putting min temperature first
 +
    listMaxTemp = []
 +
    for year, month, maxT, minT, rain, sun in list:
 +
        if maxT=="---":
 +
            continue
 +
   
 +
        listMaxTemp.append( ( float(maxT), year, month ) )
 +
 
 +
    # sort from coldest to warmest min temp
 +
    listMaxTemp.sort()
 +
    listMaxTemp.reverse()
 +
 
 +
    # find coldest temperature
 +
    warmest = listMaxTemp[0][0]
 +
 
 +
    # find all months and years with that coldest temperature
 +
    print( "2, ", warmest, end="", sep="" )
 +
    for maxT, year, month in listMaxTemp:
 +
        if maxT == warmest:
 +
            print( ", ", year, ", ",  month, end="", sep="" )
 +
    print()
 +
 
 +
    #===============================================================
 +
    # Find the 5 sunniest months, listed in order of sun exposure
 +
    #===============================================================
 +
    # create a new list, putting min temperature first
 +
    sunniestMonthsYears = []
 +
    for year, month, maxT, minT, rain, sun in list:
 +
        if sun=="---":
 +
            continue
 +
        sun = float( sun )
 +
        sunniestMonthsYears.append( (sun, year, month) )
 +
 
 +
    # sort from coldest to warmest min temp
 +
    sunniestMonthsYears.sort()
 +
    sunniestMonthsYears.reverse()
 +
 
 +
    # find all months and years with that coldest temperature
 +
    print( "3", end="" )
 +
    for i in range( min( 5, len( sunniestMonthsYears) ) ):
 +
        sun, year, month = sunniestMonthsYears[i]
 +
        print( ", {0:1.1f}, {1:1}, {2:1}".format( sun, year, month), end="", sep="" )
 +
    print()
 +
 
 +
 
 +
 
 +
if __name__=="__main__":
 +
    main()
 +
 
 +
</source>
 +
<br />
 +
==Problem 2==
 +
<br />
 +
<source lang="python">
 +
# Hw11 Problem 2
 +
# D. Thiebaut
 +
# Cars, Trucks, and Super-Trucks.
 +
# Example of inheritance.
 +
 
 +
from graphics import *
 +
W = 600
 +
H = 500
 +
 
 +
#----------------------------------------------------------------
 +
class Wheel:
 +
    """A class with two concentric circles"""
 +
 
 +
    def __init__( self, center, r1, r2 ):
 +
        self.circ1 = Circle( center, r1 )
 +
        self.circ2 = Circle( center, r2 )
 +
        r1, r2 = min( r1, r2 ), max( r1, r2 )
 +
        self.radius1 = r1
 +
        self.radius2 = r2
 +
       
 +
    def draw( self, win ):
 +
        self.circ2.draw( win )
 +
        self.circ1.draw( win )
 +
 
 +
    def setFill( self, color1, color2 ):
 +
        self.circ1.setFill( color1 )
 +
        self.circ2.setFill( color2 )
 +
 
 +
    def getRadius1( self ):
 +
        return self.radius1
 +
 
 +
    def getRadius2( self ):
 +
        return self.radius2
 +
 
 +
    def move( self, dx, dy ):
 +
        self.circ1.move( dx, dy )
 +
        self.circ2.move( dx, dy )
 +
 
 +
#----------------------------------------------------------------
 +
class Car:
 +
    """a class containing a rectangle and 2 wheels"""
 +
 
 +
    def __init__( self, P1, P2 ):
 +
        """constructs the car.  The top-left and bottom-right points
 +
        defining the body of the car are given."""
 +
        #self.P1 = P1
 +
        #self.P2 = P2
 +
        self.width = abs( P1.getX()-P2.getX() )
 +
        self.height= abs( P1.getY()-P2.getY() )
 +
       
 +
        #--- define rectangle---
 +
        self.body    = Rectangle( P1, P2 )
 +
 
 +
        #--- add a triangle for windshield ---
 +
        P3 = Point( P1.getX()+self.width//5, P1.getY() )
 +
        P4 = Point( P1.getX()+self.width//3, P1.getY() )
 +
        P5 = Point( P4.getX(), P1.getY()-self.height//2 )
 +
        self.windshield = Polygon( P3, P4, P5 )
 +
        self.windshield.setFill( "lightblue" )
 +
       
 +
        #--- and the two wheels ---
 +
        center1      = Point( P1.getX()+self.width/8, P2.getY() )
 +
        center2      = Point( P1.getX()+self.width*7/8, P2.getY() )
 +
        radius2      = self.height/3
 +
        radius1      = radius2/2
 +
        self.wheel1  = Wheel( center1, radius1, radius2 )
 +
        self.wheel2  = Wheel( center2, radius1, radius2 )
 +
 
 +
    def draw( self, win ):
 +
        """draw rectangle  2 wheels on window"""
 +
        self.body.draw( win )
 +
        self.windshield.draw( win )
 +
        self.wheel1.draw( win )
 +
        self.wheel2.draw( win )
 +
 
 +
    def setFill( self, color1, color2, color3 ):
 +
        """defines the color of the car.  First is body, then inside wheel, then tire color"""
 +
        self.body.setFill( color1 )
 +
        self.wheel1.setFill( color2, color3 )
 +
        self.wheel2.setFill( color2, color3 )
 +
 
 +
    def move( self, dx, dy ):
 +
        """defines direction of movement for all 3 elements of car"""
 +
        self.body.move( dx, dy )
 +
        self.windshield.move( dx, dy )
 +
        self.wheel1.move( dx, dy )
 +
        self.wheel2.move( dx, dy )
 +
     
 +
class Truck( Car ):
 +
    def __init__( self, P1, P2, color1, color2, color3 ):
 +
        super().__init__( P1, P2 )
 +
        super().setFill( color1, color2, color3 )
 +
        P4 = Point( P1.getX()+self.width//3, P1.getY() )
 +
        P5 = Point( self.body.getP2().getX(), P1.getY()-self.height//2 )
 +
        self.top = Rectangle( P4, P5 )
 +
        self.top.setFill( color1 )
 +
       
 +
    def draw( self, win ):
 +
        super().draw( win )
 +
        self.top.draw( win )
 +
 
 +
    def move( self, dx, dy ):
 +
        self.top.move( dx, dy )
 +
        super().move( dx, dy )
 +
 
 +
class SuperTruck( Truck ):
 +
    def __init__( self, refPoint, width, height, color ):
 +
        P2 = Point( refPoint.getX()+width, refPoint.getY()+height )
 +
        super().__init__( refPoint, P2, color, "white", "black" )
 +
 
 +
        P3 = self.top.getP1()
 +
        P4 = self.top.getP2()
 +
        x3 = P3.getX()+5
 +
        y3 = P3.getY()-5
 +
        x4 = P4.getX()-5
 +
        y4 = P4.getY()+5
 +
       
 +
        self.backWindow = Rectangle( Point( x3, y3), Point( x4, y4 ) )
 +
        self.backWindow.setFill( "lightblue" )
 +
 
 +
    def draw( self, win ):
 +
        super().draw( win )
 +
        self.backWindow.draw( win )
 +
 
 +
    def move( self, dx, dy ):
 +
        self.backWindow.move( dx, dy )
 +
        super().move( dx, dy )
 +
       
 +
def main():
 +
    global W, H
 +
    win = GraphWin( "wheel demo", W, H )
 +
 
 +
    car = Car( Point( 100,100 ), Point( 250, 170 ) )
 +
 
 +
    car.draw( win )
 +
    car.setFill( "red", "yellow", "black" )
 +
 
 +
    truck = Truck( Point( 300, 200 ), Point( 400, 250 ), "red", "grey", "blue" )
 +
    truck.draw( win )
 +
 
 +
    sTruck = SuperTruck( Point( 450, 300 ), 100, 75, "yellow" )
 +
    sTruck.draw( win )
 +
   
 +
    for i in range( 100 ):
 +
        car.move( -2, 0 )
 +
        truck.move( -2, 0 )
 +
        sTruck.move( -2, 0 )
 +
       
 +
    win.getMouse()
 +
   
 +
main()
 +
 
 +
</source>
 
<br />
 
<br />
 
</showafterdate>
 
</showafterdate>
 
<br />
 
<br />
 +
<onlydft>
 +
=VPL=
 +
==Problem 1==
 +
[09:54:35] ~/Desktop/Dropbox/111/HW11$: vpl2wiki.py vpl1.txt
 +
==vpl_run.sh==
 +
<br />
 +
<source lang="bash">
 +
</source>
 +
<br />
 +
==vpl_evaluate.sh==
 +
<br />
 +
<source lang="bash">
 +
#! /bin/bash
 +
 +
cat  > vpl_execution <<EOF
 +
#! /bin/bash
 +
 +
# --- Python ----
 +
if [[ `hostname -s` = "beowulf2" ]]; then
 +
  python=/usr/bin/python3.3
 +
else
 +
  python=/usr/local/bin/python3.4
 +
fi
 +
 +
 +
 +
\$python evaluate.py
 +
 +
EOF
 +
 +
chmod +x vpl_execution
 +
 +
 +
</source>
 +
<br />
 +
==hw11_1sol.py==
 +
<br />
 +
<source lang="python">
 +
# hw1_11sol.py
 +
# D. Thiebaut
 +
# 2015
 +
 +
def getData():
 +
    #return open( "armagh.txt", "r" ).read()
 +
 +
    fileName = input( "> " )
 +
    while True:
 +
        try:
 +
            text = open( fileName, "r" ).read()
 +
            return text
 +
        except:
 +
            print( "Invalid file name.  Reenter" )
 +
        fileName = input( "> " )
 +
 +
def main():
 +
    text = getData()
 +
    lines = text.split( "\n" )
 +
 +
    # create a list of just year, month, minT, maxT, rain, and sun
 +
    list = []
 +
    for line in lines:
 +
        line = line.strip()
 +
        if len( line ) == 0:
 +
            continue
 +
 +
        # skip line that do not start with a year
 +
        if not line[0] in ['1', '2']:
 +
            continue
 +
 +
        # remove stars and "Provisional" and split
 +
        fields = line.replace( '*', '' ).replace( 'Provisional', '' ).split( )
 +
 +
        # split line into variables
 +
        if len( fields ) == 7:
 +
            year, month, maxT, minT, af, rain, sun = fields
 +
        else:
 +
            continue
 +
 +
        # create tuple and record it in list
 +
        tuple = ( year, month, maxT, minT, rain, sun )
 +
        list.append( tuple )
 +
 +
    #===============================================================
 +
    # Find coldest months and years on record
 +
    #===============================================================
 +
    # create a new list, putting min temperature first
 +
    listMinTemp = []
 +
    for year, month, maxT, minT, rain, sun in list:
 +
        if minT=="---":
 +
            continue
 +
 +
        listMinTemp.append( ( float(minT), year, month ) )
 +
 +
    # sort from coldest to warmest min temp
 +
    listMinTemp.sort()
 +
 +
    # find coldest temperature
 +
    coldest = listMinTemp[0][0]
 +
 +
    # find all months and years with that coldest temperature
 +
    print( "1, ", coldest, end="", sep="" )
 +
    for minT, year, month in listMinTemp:
 +
        if minT == coldest:
 +
            print( ", ", year, ", ",  month,  end="", sep="" )
 +
    print()
 +
 +
    #===============================================================
 +
    # Find warmest months and years on record
 +
    #===============================================================
 +
    # create a new list, putting min temperature first
 +
    listMaxTemp = []
 +
    for year, month, maxT, minT, rain, sun in list:
 +
        if maxT=="---":
 +
            continue
 +
 +
        listMaxTemp.append( ( float(maxT), year, month ) )
 +
 +
    # sort from coldest to warmest min temp
 +
    listMaxTemp.sort()
 +
    listMaxTemp.reverse()
 +
 +
    # find coldest temperature
 +
    warmest = listMaxTemp[0][0]
 +
 +
    # find all months and years with that coldest temperature
 +
    print( "2, ", warmest, end="", sep="" )
 +
    for maxT, year, month in listMaxTemp:
 +
        if maxT == warmest:
 +
            print( ", ", year, ", ",  month, end="", sep="" )
 +
    print()
 +
 +
    #===============================================================
 +
    # Find the 5 sunniest months, listed in order of sun exposure
 +
    #===============================================================
 +
    # create a new list, putting min temperature first
 +
    sunniestMonthsYears = []
 +
    for year, month, maxT, minT, rain, sun in list:
 +
        if sun=="---":
 +
            continue
 +
        sun = float( sun )
 +
        sunniestMonthsYears.append( (sun, year, month) )
 +
 +
    # sort from coldest to warmest min temp
 +
    sunniestMonthsYears.sort()
 +
    sunniestMonthsYears.reverse()
 +
 +
    # find all months and years with that coldest temperature
 +
    print( "3", end="" )
 +
    for i in range( min( 5, len( sunniestMonthsYears) ) ):
 +
        sun, year, month = sunniestMonthsYears[i]
 +
        print( ", {0:1.1f}, {1:1}, {2:1}".format( sun, year, month), end="", sep="" )
 +
    print()
 +
 +
 +
 +
if __name__=="__main__":
 +
    main()
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
</source>
 +
<br />
 +
==evaluate.py==
 
<br />
 
<br />
 +
<source lang="python">
 +
# evaluate.py
 +
# D. Thiebaut
 +
# This program is used to test a student's python program on Moodle.
 +
 +
import sys
 +
import random
 +
import subprocess
 +
 +
#--- GLOBALS ---
 +
#--- define what the student program is called, and what the solution
 +
#--- program name is.
 +
 +
debug  = False
 +
module = "hw11_1"
 +
solutionModule = module + "sol"
 +
userOutSplitPattern = ""      # pattern used to start recording the user
 +
                              # output.  Useful when program does several
 +
                              # input() statements, and user output starts
 +
                              # after that.
 +
stripOutputsBeforeCompare = True
 +
                              # set to True if extra spaces at beginning or
 +
                              # end of user output is ok
 +
 +
interpreter = sys.executable
 +
 +
def commentLong( line ):
 +
    print( "<|--\n" + line  + "\n --|>" )
 +
 +
def commentShort( text ):
 +
    print( "Comment :=>> " + text )
 +
 +
def comment( text ):
 +
    commentShort( text )
 +
 +
def printGrade( grade ):
 +
    print( "Grade :=>> ", grade )
 +
 +
# remove if __name__==...
 +
def removeIfNameEqMain( fileName ):
 +
    file = open( fileName, "r" )
 +
    lines = file.read()
 +
    file.close()
 +
 +
    newLines = ""
 +
    for line in lines.split( "\n" ):
 +
        if line.find( "__name__" )!=-1 and line.find( "__main__" )!=-1 and line.find( "if True" )==-1:
 +
            line = "if True: #" + line
 +
        newLines += line + "\n"
 +
 +
    # write it back
 +
    file = open( fileName, "w" )
 +
    file.write( newLines )
 +
    file.close()
 +
 +
# add if __name__=="__main__": to the program
 +
def addIfNameEqMain( fileName ):
 +
    file = open( fileName, "r" )
 +
    lines = file.read()
 +
    file.close()
 +
 +
    newLines = ""
 +
    for line in lines.split( "\n" ):
 +
        if line.find( "main()" )==0:
 +
            line = 'if __name__=="__main__":  main()'
 +
        newLines += line + "\n"
 +
 +
    # write it back
 +
    file = open( fileName, "w" )
 +
    file.write( newLines )
 +
    file.close()
 +
 +
def createEmptyFile( fileName ):
 +
    file = open( fileName, "w" )
 +
    file.write( "chivenordata.txt\n\n\n" )
 +
    file.close()
 +
 +
# generateInputFileWithRandomInputs
 +
# generate a file with name "inputFileName" with some random input
 +
# for the program.
 +
# MAKE SURE TO EDIT THIS TO MATCH THE PROGRAM BEING TESTED
 +
def generateInputFile( inputFileName, i ):
 +
    #--- we don't need an input file for stdin, but we'll generate a
 +
    #--- dummy one nonetheless
 +
    open( inputFileName, "w" ).write( "chivenordata.txt\n" )
 +
 +
    return "chivenordata.txt"
 +
 +
# checkForFunctionPresence
 +
# checks that "functionName" is defined and called in the program.
 +
# MAKE SURE TO EDIT TO MATCH PROGRAM BEING TESTED
 +
def checkForFunctionPresence( module, functionName ):
 +
    foundDef = False
 +
    foundCall = False
 +
 +
    for line in open( module+".py", "r" ).readlines():
 +
        # remove comments
 +
        idx = line.find( "#" )
 +
        if ( idx >=0 ): line = line[0:idx]
 +
 +
        if line.startswith( "def " + functionName + "(" ):
 +
            foundDef = True
 +
            continue
 +
        if line.startswith( "def " + functionName + " (" ):
 +
            foundDef = True
 +
            continue
 +
        if line.find( functionName+"(" ) != -1:
 +
            foundCall = True
 +
            continue
 +
 +
    return (foundDef, foundCall)
 +
 +
 +
 +
# ==================================================================
 +
# NO EDITS NEEDED BELOW!
 +
# ==================================================================
 +
 +
def clearLog():
 +
    open( "log.txt", "w" ).write( "" )
 +
 +
def log( message ):
 +
    file = open( "log.txt", "a" )
 +
    file.write( message + "\n" )
 +
    file.flush()
 +
    file.close()
 +
 +
 +
# checkModuleRunsOK: runs the module as a shell subprocess and
 +
# look for errors in the output.  This is required, because otherwise
 +
# importing the module in this program will make this program crash.
 +
# It's not possible (as far as I can tell0 to catch exceptions from
 +
# the import or __module__ statements.
 +
# returns True, none if no errors, otherwise False, string if there's
 +
# an exception, and the error message (string) is in the returned 2nd
 +
# arg.
 +
# The module name is assumed to not include ".py"
 +
def checkModuleRunsOk( module, inputFileName ):
 +
    global interpreter
 +
    p = subprocess.Popen( [ interpreter, module+".py" ],
 +
                          stdout=subprocess.PIPE,
 +
                          stderr=subprocess.PIPE,
 +
                          stdin=subprocess.PIPE)
 +
 +
    #print( "inputFileName = ", inputFileName )
 +
    #print( "open( inputFileName, r).read() = ", open( inputFileName, "r" ).read() )
 +
 +
    p.stdin.write( bytes( open( inputFileName, "r" ).read(), 'UTF-8' ) )
 +
    data = p.communicate( )
 +
    p.stdin.close()
 +
 +
    error = data[1].decode( 'UTF-8' )
 +
    if len( error ) > 1:
 +
        return False, error
 +
    return True, None
 +
 +
 +
# extractTextFromErrorMessage( sys_exc_info ):
 +
def extractTextFromErrorMessage( sys_exc_info ):
 +
    if debug: print( "sys_exec_info = ", sys_exc_info )
 +
    text = ""
 +
    for field in sys_exc_info:
 +
        if type( field )==type( " " ):
 +
            text += field + "\n"
 +
    return text
 +
 +
# runModule:
 +
# runs the module, passes it data from the input file on its stdin
 +
# and get its output on stdout captured in outputFileName.
 +
# We assume the module will not crash, because we already tested
 +
# it with checkModuleRunsOk().
 +
def runModule( module, inputFileName, outputFileName ):
 +
    global userOutSplitPattern
 +
 +
    error = False
 +
 +
    #--- make stdin read information from the text file
 +
    sys.stdin = open( inputFileName, "r" )
 +
 +
    #--- capture the stdout of the program to test into a file
 +
    saveStdOut = sys.stdout
 +
    saveStdErr = sys.stderr
 +
 +
    sys.stdout = open( outputFileName, "w" )
 +
    sys.stderr = open( "errorOut", "w" )
 +
 +
    #--- run the student program ---
 +
    try:
 +
        _module = __import__(  module  )
 +
        _module.main()
 +
    except:
 +
        error = True
 +
        sys.stderr.close()
 +
        sys.stderr = saveStdErr
 +
        sys.stdout.close()
 +
        sys.stdout = saveStdOut
 +
        text = sys.exc_info()[0]
 +
        text = extractTextFromErrorMessage( text )
 +
        #print( "*** sys.exc_info() = ", text )
 +
        text = open( outputFileName, "r" ).read() + "\n" + text
 +
        return error, text, 0
 +
 +
    #--- filter out junk from output of program ---
 +
    sys.stdout.close()
 +
    sys.stdout = saveStdOut
 +
    sys.stderr.close()
 +
    sys.stderr = saveStdErr
 +
 +
    file = open( outputFileName, "r" )
 +
    text = file.read()
 +
    file.close()
 +
    if debug:
 +
        print( "runModule( ", module, " ) returns text = <", text , ">" )
 +
 +
    return False, text, 0
 +
 +
def removeBlankLines( lines ):
 +
    newLines = []
 +
    log( "removeBlankLines: lines = " + str( lines ) )
 +
    for line in lines.split( "\n" ):
 +
        if len( line )==0:
 +
            continue
 +
        newLines.append( line )
 +
 +
    return ( "\n".join( newLines ) ) + "\n"
 +
 +
 +
def compareUserExpected( inputLines, userOutText, expectedOutText ):
 +
    global stripOutputsBeforeCompare
 +
 +
    log( "compareUserExpected:\nuserOutText = " + userOutText )
 +
    log( "expectedOutText = " + expectedOutText )
 +
 +
    userOutText = removeBlankLines( userOutText )
 +
    expectedOutText = removeBlankLines( expectedOutText )
 +
    misMatchLineNumbers = []
 +
    userTextOutLines = userOutText.split( "\n" )
 +
    expectedOutTextLines = expectedOutText.split( "\n" )
 +
 +
    log( "-" * 60 )
 +
    log( "userTextOutLines = " + str( userTextOutLines ) )
 +
    log( "expectedOutTextLines = " + str( expectedOutTextLines ) )
 +
    log( "-" * 60 )
 +
 +
    for i in range( len( userTextOutLines ) ):
 +
        lineNo = i+1
 +
        userLine = userTextOutLines[i]
 +
        if i >= len( expectedOutTextLines ):
 +
            misMatchLineNumbers.append( lineNo )
 +
            break
 +
        expectedLine = expectedOutTextLines[i]
 +
        log( "compareUserExpected: comparing:\n  "+userLine+"\n  "+expectedLine )
 +
        if stripOutputsBeforeCompare:
 +
            userLine = userLine.strip()
 +
            expectedLine = expectedLine.strip()
 +
        if userLine != expectedLine:
 +
            log( "\ndifference:\n  user    >" + userTextOutLines[i] + "<" )
 +
            log( "\n  expected >" + expectedOutTextLines[i] + "<" )
 +
            misMatchLineNumbers.append( lineNo )
 +
 +
    return misMatchLineNumbers
 +
 +
 +
 +
def compareUserExpectedNumbers( inputLines, userOutText, expectedOutText ):
 +
    global stripOutputsBeforeCompare
 +
 +
    log( "compareUserExpected:\nuserOutText = " + userOutText )
 +
    log( "expectedOutText = " + expectedOutText )
 +
 +
    userOutText = removeBlankLines( userOutText )
 +
    expectedOutText = removeBlankLines( expectedOutText )
 +
    misMatchLineNumbers = []
 +
    userTextOutNumbers = userOutText.replace( ",", "" ).split()
 +
    expectedOutNumbers = expectedOutText.replace( ",", "" ).split(  )
 +
    userTextOutNumbers = [k.strip() for k in userTextOutNumbers ]
 +
    expectedOutNumbers = [k.strip() for k in expectedOutNumbers ]
 +
 +
    log( "-" * 60 )
 +
    log( "userTextOutNumbers = " + str( userTextOutNumbers ) )
 +
    log( "expectedOutNumbers = " + str( expectedOutNumbers ) )
 +
    log( "-" * 60 )
 +
 +
    count = 0
 +
    for i in range( len( userTextOutNumbers ) ):
 +
        if userTextOutNumbers[i] in expectedOutNumbers:
 +
            count += 1
 +
        else:
 +
            misMatchLineNumbers.append( userTextOutNumbers[i] )
 +
 +
 +
    return count, len( expectedOutNumbers )
 +
 +
 +
 +
def main():
 +
    global module
 +
    global solutionModule
 +
    #--- remove if __name__=="__main__" statement, if it's here...
 +
    addIfNameEqMain( module+ ".py" )
 +
    addIfNameEqMain( solutionModule+ ".py" )
 +
 +
    #--- clear debug log ---
 +
    clearLog()
 +
 +
    #--- generate a dummy file, just to test the module ---
 +
    inputLines = generateInputFile( "input.txt", 0 )
 +
 +
    #--- check that the main module uses a main() function
 +
    """
 +
    foundDef, foundCall = checkForFunctionPresence( module, "main" )
 +
 +
    if (not foundDef) or (not foundCall):
 +
        commentShort( "-Missing main() program" )
 +
        commentShort( "Your program must use a main() function." )
 +
        commentShort( "(make sure you spell it exactly \"main()\"!" )
 +
        printGrade( 40 )
 +
        return
 +
    """
 +
 +
    # test that module runs on its own without problem
 +
    createEmptyFile( "input.txt" )
 +
    Ok, errorMessage = checkModuleRunsOk( module, "input.txt" )
 +
    if not Ok:
 +
        commentLong( "- Your program crashed...\n"
 +
                        + "Error message:\n"
 +
                    + errorMessage + "\n" )
 +
        printGrade( 30 )
 +
        return
 +
 +
    score = 30
 +
    dummyFile = open( "dummy.txt", "w" )
 +
    dummyFile.write( "RS\nRS\nRS\nRS\nRS\nRS\nRS\nRS\nRS\nRS\nRS\n" )
 +
    dummyFile.close()
 +
 +
    #--- run several tests with a different input file for each ---
 +
    for testNo in range( 1 ):
 +
        if debug: print( "\n\n============== Test", testNo, "===============" )
 +
        log( "\n\n============== Test %d ===============" % testNo )
 +
 +
        comment( "- TEST NUMBER %d" % testNo )
 +
 +
        inputLines = generateInputFile( "input.txt", testNo )
 +
        if debug: print( "inputLines: ", inputLines )
 +
        if debug: print( "input.txt: ", open( "input.txt", "r" ).read() )
 +
 +
        # generate exptected output
 +
        dummy, expectedOutText, score2 = runModule( solutionModule, "input.txt", "expectedOut" )
 +
        if debug: print( "runModule solution:", dummy, expectedOutText, score2 )
 +
 +
        # generate user output
 +
        error, userOutText, score2  = runModule( module, "input.txt", "userOut" )
 +
        if debug: print( "runModule user:", error, userOutText, score2 )
 +
        if error:
 +
            commentLong( "- Your program crashed...\n"
 +
                    + "Your program was tested with a file containing:\n"
 +
                    + inputLines  + "\n"
 +
                    + "Error message:\n"
 +
                    + userOutText + "\n" )
 +
            #printGrade( score)
 +
 +
        #missMatches = compareUserExpected( inputLines, userOutText, expectedOutText )
 +
        count, maxCount = compareUserExpectedNumbers( inputLines, userOutText, expectedOutText )
 +
        if debug: print( " count = ", count, " maxCount = ", maxCount )
 +
        if count != maxCount:
 +
            commentLong( "- Incorrect output...\n"
 +
                    +"Your program was tested with "
 +
                    + inputLines  + "\n"
 +
                    +"Expected output:\n"
 +
                    +expectedOutText + "\n"
 +
                    +"Your output:\n"
 +
                    +userOutText + "\n" )
 +
            score = (100 * count) // maxCount
 +
        else:
 +
            commentLong( "- Your program passes the test\n"
 +
                        +"with the input file containing:\n"
 +
                        + inputLines + "\n" )
 +
 +
            score = 100
 +
 +
 +
    printGrade( max( 20, score ) )
 +
 +
main()
 +
 +
 +
 +
</source>
 
<br />
 
<br />
 +
 +
 +
 +
</onlydft>
 
<br />
 
<br />
 
<br />
 
<br />

Latest revision as of 13:20, 23 April 2015

--D. Thiebaut (talk) 17:20, 12 April 2015 (EDT)


<showafterdate after="20150415 12:00" before="20150601 00:00">


This Homework is due on Tuesday evening, 4/21/15, at 11:55 p.m.


Problem #1: Temperatures in the UK

HistoricStationDataUKWeather.png


Assignment

  • Your assignment is to write a program that reads weather data from a text file, then processes the data, and finally outputs the answers to several questions.
  • Call your program hw11_1.py

The Weather Data Files


  • The British government has been keeping track of temperatures in several cities of the U.K. The official Web site where the data is available is http://www.metoffice.gov.uk/climate/uk/stationdata/. The records of temperatures for 37 towns/cities of the UK for the past few years, going back in some cases to 1853, are kept on this site.


  • The data recorded consists of these quantities
  • Mean daily maximum temperature (tmax)
  • Mean daily minimum temperature (tmin)
  • Days of air frost (af)
  • Total rainfall (rain)
  • Total sunshine duration (sun)
(More information can be found here.)


  • The format for the data is CSV.
  • The data from the UK Web site have been mirrored on a Smith server: http://cs.smith.edu/~dthiebaut/UKTemperatures/. You will need to download a few files from that site to develop and test your program.
  • The name of a file is simply the name of the U.K. town, all lowercase, suffixed by "data.txt."


Format of the data


  • Instead of relying on the weather site in the U.K., we have mirrored the data files on a Smith server.
  • Download one of the files from http://cs.smith.edu/~dthiebaut/UKTemperatures/, say armaghdata.txt, and take a look at it. Use Notepad, TextEdit or your favorite text editor to open the file.
  • You will notice that when measurements are missing, they are replaced by "---". Your program should not skip measurements that are missing.
  • Sometimes, especially at the end of the file, measurements are suffixed with an asterisk (*). Your program should discard the asterisk, and treat the data as valid.
  • Some lines have the word "Provisional" at the end. Your program should treat these lines the same as regular line, and should not skip them.


Input


  • Your program should prompt the user for a file name. The user will supply the name of one of the text files that will have been previously downloaded from the Smith Web site. In other words, your program simply needs to read a text file and does not need to access the Web.
  • If the user provides an invalid file name, your program will keep on prompting the user for a new name. Your program will only start processing the data once it has been given a valid file name.


Processing


  • You must use the method illustrated in the Animals and Presidents problems of Lab 11 to process the data.
  • All temperatures should be reported in degrees Celsius which is the system used in the U.K. (so you do not need to transform the temperatures).


Questions


Question 1
In what year or years was the coldest temperature recorded? If the coldest temperature appears several times, list all the years and month in which it will have been reported. The format of the output is illustrated in a later section.


Question 2
In what year or years was the warmest temperature recorded? If the warmest temperature appears several times, list all the years and month in which it will have been reported. The format of the output is illustrated in a later section.
Question 3
What are the 5 sunniest months and years for the given city? The format of the output is illustrated below.


Output Format


  • Here is the expected output for armaghdata.txt:


> armagh.txt
Invalid file name, please re-enter
> armaghdata.txt
1, -4.2, 1878, 12, 1895, 2
2, 23.8, 1995, 8, 1989, 7
3, 256.0, 1940, 6, 252.9, 1949, 6, 251.6, 1935, 5, 244.1, 1957, 6, 243.8, 1989, 7


and here is the expected output for ballpatrickdata.txt:
> ballypatrickdata.txt
1, -1.8, 1979, 1
2, 20.0, 1995, 8
3, 279.3, 1975, 5, 272.6, 1976, 8, 253.7, 1977, 5, 247.2, 1984, 5, 245.6, 1974, 4

Note that each line is prefixed with a number, identifying the question for which the line is the answer.
The order in which the years of min or max temperature are listed is unimportant.
All the floating point numbers are printed with 1 decimal after the point.
The sunniest months are listed in order of decreasing exposure.
Note, also, that the output is in CSV form. A coma separates all the values. No extra spaces should appear in front of comas.

Moodle Submission

  • Submit your program in the Moodle HW11 PB1 section. You will not be allowed to evaluate this program, so make sure you test it thoroughly.



Problem 2: Class Inheritance


Preparation


  • Create a file called car.py, containing the following code:


# car.py
# CSC111
# This file contains the definition of a Wheel and a Car
# The car is a convertible, with a rectangular body,
# a windshield, and two wheels.
from graphics import *

#----------------------------------------------------------------
class Wheel:
    """A class with two concentric circles"""

    def __init__( self, center, r1, r2 ):
        self.circ1 = Circle( center, r1 )
        self.circ2 = Circle( center, r2 )
        r1, r2 = min( r1, r2 ), max( r1, r2 )
        self.radius1 = r1
        self.radius2 = r2
        
    def draw( self, win ):
        self.circ2.draw( win )
        self.circ1.draw( win )

    def setFill( self, color1, color2 ):
        self.circ1.setFill( color1 )
        self.circ2.setFill( color2 )

    def getRadius1( self ):
        return self.radius1

    def getRadius2( self ):
        return self.radius2

    def move( self, dx, dy ):
        self.circ1.move( dx, dy )
        self.circ2.move( dx, dy )

#----------------------------------------------------------------
class Car:
    """a class containing a rectangle and 2 wheels"""

    def __init__( self, P1, P2 ):
        """constructs the car.  The top-left and bottom-right points
        defining the body of the car are given."""
        #self.P1 = P1
        #self.P2 = P2
        self.width = abs( P1.getX()-P2.getX() )
        self.height= abs( P1.getY()-P2.getY() )
        
        #--- define rectangle---
        self.body    = Rectangle( P1, P2 )

        #--- add a triangle for windshield ---
        P3 = Point( P1.getX()+self.width//5, P1.getY() )
        P4 = Point( P1.getX()+self.width//3, P1.getY() )
        P5 = Point( P4.getX(), P1.getY()-self.height//2 )
        self.windshield = Polygon( P3, P4, P5 )
        self.windshield.setFill( "lightblue" )
        
        #--- and the two wheels ---
        center1      = Point( P1.getX()+self.width/8, P2.getY() )
        center2      = Point( P1.getX()+self.width*7/8, P2.getY() )
        radius2      = self.height/3
        radius1      = radius2/2
        self.wheel1  = Wheel( center1, radius1, radius2 )
        self.wheel2  = Wheel( center2, radius1, radius2 )

    def draw( self, win ):
        """draw rectangle  2 wheels on window"""
        self.body.draw( win )
        self.windshield.draw( win )
        self.wheel1.draw( win )
        self.wheel2.draw( win )

    def setFill( self, color1, color2, color3 ):
        """defines the color of the car.  First is body, then inside wheel, then tire color"""
        self.body.setFill( color1 )
        self.wheel1.setFill( color2, color3 )
        self.wheel2.setFill( color2, color3 )

    def move( self, dx, dy ):
        """defines direction of movement for all 3 elements of car"""
        self.body.move( dx, dy )
        self.windshield.move( dx, dy )
        self.wheel1.move( dx, dy )
        self.wheel2.move( dx, dy )


  • Create a new program called hw11_2.py with the code below:


# hw11_2.py
# your name here
# 
# This program draws a car on the graphics window
# and moves it a few pixels.
from graphics import * # import all the graphic elements (Rectangles, etc.)
from car import *        # import the Wheel and Car classes from car.py
WIDTH = 600
HEIGHT= 600
         
def main():
    global W, H
    win = GraphWin( "Put your name here", WIDTH, HEIGHT )

    # create a car
    car = Car( Point( 100,100 ), Point( 250, 170 ) )

    # set the color of its different parts and draw it
    car.setFill( "red", "yellow", "black" )
    car.draw( win )
    
    # move it
    for i in range( 100 ):
        car.move( -2, 0 )
        
    win.getMouse()
    
if __name__=="__main__":
    main()


Assignment


Your assignment is to create two new classes inside the hw11_2.py program. The first class will be called Truck, and is derived from Car. The second class is called SuperTruck, and is derived from Truck.

Truck Class

TruckDerivedFromCar.png


  • The Truck must be derived from the Car class.
  • The constructor for the Truck is given two points and three colors. Creating a truck, drawing it, and moving it a few pixels is illustrated below. The corresponding truck is shown on the right hand side.


    truck = Truck( Point( 300, 200 ), Point( 400, 250 ), "red", "grey", "blue" )
    truck.draw( win )
    for i in range( 20 ):
         truck.move( -2, 0 )





SuperTruck Class

SuperTruckDerivedFromTruck.png


  • The SuperTruck must be derived from the Truck class.
  • Creating a SuperTruck object, drawing it, and moving it a few pixels to the left is illustrated below. The corresponding image is shown to the right. A SuperTruck object is constructed by giving it a reference point, which is the top-left point of the rectangle forming the body of the truck, a width, and a height for the body of the truck, and the color of the body and top of the super truck.

The top of the SuperTruck extends from the windshield to the end of the body.

    sTruck = SuperTruck( Point( 450, 300 ), 100, 75, "yellow" )
    sTruck.draw( win )    
    for i in range( 20 ):
         sTruck.move( -2, 0 )






Submission


  • Submit a copy of the graphics window showing a car, a truck and a super-truck. Look for the HW11 PB2 Image section on Moodle. Assuming that we use the code above to create them, the image created by your program should be as close to the one below as possible (except for the text in grey, of course):


CarTruckSuperTruck.png

  • Submit a copy of your program hw11_2.py in the HW11 PB2 section on Moodle.

</showafterdate>

<showafterdate after="20150422 00:00" before="20150601 00:00">

Solution Programs


Problem 1


# hw11_1.py
# D. Thiebaut
# This program prompts the user for a file name that contains data about
# weather conditions recording a given month in a British city.   The source
# of the data is taken from http://www.metoffice.gov.uk/climate/uk/stationdata/
# This program outputs several quantities, including the years and months when 
# the coldest temperature was recorded, the year the warmest temperature was recorded,
# the 5 sunniest months and years.

def getData():
    #return open( "armagh.txt", "r" ).read()

    fileName = input( "> " )
    while True:
        try:
            text = open( fileName, "r" ).read()
            return text
        except:
            print( "Invalid file name.  Reenter" )
        fileName = input( "> " )

def main():
    text = getData()
    lines = text.split( "\n" )

    # create a list of just year, month, minT, maxT, rain, and sun
    list = []
    for line in lines:
        line = line.strip()
        if len( line ) == 0:
            continue

        # skip line that do not start with a year
        if not line[0] in ['1', '2']:
            continue

        # remove stars and "Provisional" and split
        fields = line.replace( '*', '' ).replace( 'Provisional', '' ).split( )

        # split line into variables
        if len( fields ) == 7:
            year, month, maxT, minT, af, rain, sun = fields
        else:
            continue

        # create tuple and record it in list
        tuple = ( year, month, maxT, minT, rain, sun )
        list.append( tuple )

    #===============================================================
    # Find coldest months and years on record
    #===============================================================
    # create a new list, putting min temperature first
    listMinTemp = []
    for year, month, maxT, minT, rain, sun in list:
        if minT=="---":
            continue
    
        listMinTemp.append( ( float(minT), year, month ) )

    # sort from coldest to warmest min temp
    listMinTemp.sort()

    # find coldest temperature
    coldest = listMinTemp[0][0]

    # find all months and years with that coldest temperature
    print( "1, ", coldest, end="", sep="" )
    for minT, year, month in listMinTemp:
        if minT == coldest:
            print( ", ", year, ", ",  month,  end="", sep="" )
    print()

    #===============================================================
    # Find warmest months and years on record
    #===============================================================
    # create a new list, putting min temperature first
    listMaxTemp = []
    for year, month, maxT, minT, rain, sun in list:
        if maxT=="---":
            continue
    
        listMaxTemp.append( ( float(maxT), year, month ) )

    # sort from coldest to warmest min temp
    listMaxTemp.sort()
    listMaxTemp.reverse()

    # find coldest temperature
    warmest = listMaxTemp[0][0]

    # find all months and years with that coldest temperature
    print( "2, ", warmest, end="", sep="" )
    for maxT, year, month in listMaxTemp:
        if maxT == warmest:
            print( ", ", year, ", ",  month, end="", sep="" )
    print()

    #===============================================================
    # Find the 5 sunniest months, listed in order of sun exposure
    #===============================================================
    # create a new list, putting min temperature first
    sunniestMonthsYears = []
    for year, month, maxT, minT, rain, sun in list:
        if sun=="---":
            continue
        sun = float( sun )
        sunniestMonthsYears.append( (sun, year, month) )

    # sort from coldest to warmest min temp
    sunniestMonthsYears.sort()
    sunniestMonthsYears.reverse()

    # find all months and years with that coldest temperature
    print( "3", end="" )
    for i in range( min( 5, len( sunniestMonthsYears) ) ):
        sun, year, month = sunniestMonthsYears[i]
        print( ", {0:1.1f}, {1:1}, {2:1}".format( sun, year, month), end="", sep="" )
    print()



if __name__=="__main__":
    main()


Problem 2


# Hw11 Problem 2
# D. Thiebaut
# Cars, Trucks, and Super-Trucks.
# Example of inheritance.

from graphics import *
W = 600
H = 500

#----------------------------------------------------------------
class Wheel:
    """A class with two concentric circles"""

    def __init__( self, center, r1, r2 ):
        self.circ1 = Circle( center, r1 )
        self.circ2 = Circle( center, r2 )
        r1, r2 = min( r1, r2 ), max( r1, r2 )
        self.radius1 = r1
        self.radius2 = r2
        
    def draw( self, win ):
        self.circ2.draw( win )
        self.circ1.draw( win )

    def setFill( self, color1, color2 ):
        self.circ1.setFill( color1 )
        self.circ2.setFill( color2 )

    def getRadius1( self ):
        return self.radius1

    def getRadius2( self ):
        return self.radius2

    def move( self, dx, dy ):
        self.circ1.move( dx, dy )
        self.circ2.move( dx, dy )

#----------------------------------------------------------------
class Car:
    """a class containing a rectangle and 2 wheels"""

    def __init__( self, P1, P2 ):
        """constructs the car.  The top-left and bottom-right points
        defining the body of the car are given."""
        #self.P1 = P1
        #self.P2 = P2
        self.width = abs( P1.getX()-P2.getX() )
        self.height= abs( P1.getY()-P2.getY() )
        
        #--- define rectangle---
        self.body    = Rectangle( P1, P2 )

        #--- add a triangle for windshield ---
        P3 = Point( P1.getX()+self.width//5, P1.getY() )
        P4 = Point( P1.getX()+self.width//3, P1.getY() )
        P5 = Point( P4.getX(), P1.getY()-self.height//2 )
        self.windshield = Polygon( P3, P4, P5 )
        self.windshield.setFill( "lightblue" )
        
        #--- and the two wheels ---
        center1      = Point( P1.getX()+self.width/8, P2.getY() )
        center2      = Point( P1.getX()+self.width*7/8, P2.getY() )
        radius2      = self.height/3
        radius1      = radius2/2
        self.wheel1  = Wheel( center1, radius1, radius2 )
        self.wheel2  = Wheel( center2, radius1, radius2 )

    def draw( self, win ):
        """draw rectangle  2 wheels on window"""
        self.body.draw( win )
        self.windshield.draw( win )
        self.wheel1.draw( win )
        self.wheel2.draw( win )

    def setFill( self, color1, color2, color3 ):
        """defines the color of the car.  First is body, then inside wheel, then tire color"""
        self.body.setFill( color1 )
        self.wheel1.setFill( color2, color3 )
        self.wheel2.setFill( color2, color3 )

    def move( self, dx, dy ):
        """defines direction of movement for all 3 elements of car"""
        self.body.move( dx, dy )
        self.windshield.move( dx, dy )
        self.wheel1.move( dx, dy )
        self.wheel2.move( dx, dy )
      
class Truck( Car ):
    def __init__( self, P1, P2, color1, color2, color3 ):
        super().__init__( P1, P2 )
        super().setFill( color1, color2, color3 )
        P4 = Point( P1.getX()+self.width//3, P1.getY() )
        P5 = Point( self.body.getP2().getX(), P1.getY()-self.height//2 )
        self.top = Rectangle( P4, P5 )
        self.top.setFill( color1 )
        
    def draw( self, win ):
        super().draw( win )
        self.top.draw( win )

    def move( self, dx, dy ):
        self.top.move( dx, dy )
        super().move( dx, dy )

class SuperTruck( Truck ):
    def __init__( self, refPoint, width, height, color ):
        P2 = Point( refPoint.getX()+width, refPoint.getY()+height )
        super().__init__( refPoint, P2, color, "white", "black" )

        P3 = self.top.getP1()
        P4 = self.top.getP2()
        x3 = P3.getX()+5
        y3 = P3.getY()-5
        x4 = P4.getX()-5
        y4 = P4.getY()+5
        
        self.backWindow = Rectangle( Point( x3, y3), Point( x4, y4 ) )
        self.backWindow.setFill( "lightblue" )

    def draw( self, win ):
        super().draw( win )
        self.backWindow.draw( win )

    def move( self, dx, dy ):
        self.backWindow.move( dx, dy )
        super().move( dx, dy )
        
def main():
    global W, H
    win = GraphWin( "wheel demo", W, H )

    car = Car( Point( 100,100 ), Point( 250, 170 ) )

    car.draw( win )
    car.setFill( "red", "yellow", "black" )

    truck = Truck( Point( 300, 200 ), Point( 400, 250 ), "red", "grey", "blue" )
    truck.draw( win )

    sTruck = SuperTruck( Point( 450, 300 ), 100, 75, "yellow" )
    sTruck.draw( win )
    
    for i in range( 100 ):
        car.move( -2, 0 )
        truck.move( -2, 0 )
        sTruck.move( -2, 0 )
        
    win.getMouse()
    
main()


</showafterdate>


...