Difference between revisions of "CSC111 Lab 9 2015"

From dftwiki3
Jump to: navigation, search
(Classes and Objects)
Line 190: Line 190:
 
==Classes for a wheel and a Car==
 
==Classes for a wheel and a Car==
  
Below is the code we wrote in class yesterday:
+
Below is the code we wrote in class this week:
  
 
<source lang="python">
 
<source lang="python">
Line 203: Line 203:
  
 
from graphics import *
 
from graphics import *
W = 400
+
W = 400   # width of the graphics window
H = 400
+
H = 400   # height of the graphics window
  
 
#----------------------------------------------------------------
 
#----------------------------------------------------------------
Line 288: Line 288:
 
     #w.draw( win )
 
     #w.draw( win )
  
 +
    #--- create a car object ---
 
     car = Car( Point( 20, 20 ), Point( 120, 60 ) )
 
     car = Car( Point( 20, 20 ), Point( 120, 60 ) )
 
     car.setFill( "red", "yellow", "black" )
 
     car.setFill( "red", "yellow", "black" )
Line 294: Line 295:
  
  
     #--- move the wheel ---
+
     #--- move the car ---
 
     for i in range( 100 ):
 
     for i in range( 100 ):
 
         car.move( 3, 0 )
 
         car.move( 3, 0 )
Line 317: Line 318:
 
:Make this modification and run your program.  What happens?
 
:Make this modification and run your program.  What happens?
  
* Fix the '''class''' ''Car'' so that the user can specify any point in any order (top-left, bottom-right), or (top-right, bottom-left), or (bottom-left, top-right), and constructor will correctly define the body and the wheels to fit the shape defined by the two points.
+
* Fix the '''class''' ''Car'' so that the user can specify any point in any order (top-left, bottom-right), or (top-right, bottom-left), or (bottom-left, top-right), and the constructor will correctly define the body and the wheels to fit the shape defined by the two points.
  
 
* Oh, by the way, the car is a two-door convertible.  Add a door to the car.  The door should be a simple rectangle in the middle of the body of the car, between the two wheels.  (You may want to sketch the shape of the car on paper and figure out what proportions to use to position the door.)
 
* Oh, by the way, the car is a two-door convertible.  Add a door to the car.  The door should be a simple rectangle in the middle of the body of the car, between the two wheels.  (You may want to sketch the shape of the car on paper and figure out what proportions to use to position the door.)
Line 327: Line 328:
 
* Make your program create a list of 5 cars.
 
* Make your program create a list of 5 cars.
  
* Each car has a random horizontal velocity (dy=0), making it go left, or right.  Make dx and dy part of the class, i.e. make these variables '''member variables''' of the class '''Car'''.
+
* Each car has a random horizontal velocity (dx != 0, dy=0), making it go left, or right.  Make dx and dy part of the class, i.e. make these variables '''member variables''' of the class '''Car'''.
  
 
* Make your program move all 5 cars at the same time, until all the cars have exited the window.  As soon as the cars all disappear your program will stop.  Think of an efficient way to do this...  This is a bit tricky...  (But we are at a time in the semester where you can deal with tricky questions... :-)
 
* Make your program move all 5 cars at the same time, until all the cars have exited the window.  As soon as the cars all disappear your program will stop.  Think of an efficient way to do this...  This is a bit tricky...  (But we are at a time in the semester where you can deal with tricky questions... :-)
  
==Fish==
 
 
This section is reported to [[CSC111 Lab 11| Lab 11]]...
 
 
* Point your browser to http://maven.smith.edu/~111c/index.html
 
 
* See all the fish?  Make a note of one of the fish, and get a copy of its file as follows
 
 
  getcopy fishxx.gif            ''(replace xx by the actual number of the fish you want)''
 
 
* Write a new graphics program and copy/paste the following code in it:
 
<br />
 
 
<source lang="python">
 
.
 
 
from graphics import *
 
H = 400
 
W = 400
 
 
def waitForClick( win, message ):
 
    """ waitForClick: stops the GUI and displays a message. 
 
    Returns when the user clicks the window. The message is erased."""
 
 
    # wait for user to click mouse to start
 
    startMsg = Text( Point( win.getWidth()/2, win.getHeight()/2 ), message )
 
    startMsg.draw( win )    # display message
 
    win.getMouse()          # wait
 
    startMsg.undraw()      # erase
 
 
 
def main():
 
    global H, W
 
    win = GraphWin( "Fish Tank", W, H )
 
    waitForClick( win, "click to start" )
 
 
    fish = Image( Point( W/2, H/2 ), "fish15.gif" )  # replace 15 by the number of your fish
 
    fish.draw( win )
 
 
    waitForClick( win, "click to end" )
 
    win.close()
 
 
main()
 
 
 
.
 
</source>
 
 
* Add a for loop and make the object ''fish'' move by dx, dy some fixed number of steps...
 
 
* Create a an new class which is a fish, with its own file name, and its own dx and dy.
 
 
* Create an object issued from the class.  Verify that you can make the object move on the screen.
 
 
* Create a school of several fish that move around the screen.  The fish may move in opposite directions, but we'll assume that all fish move in the direction of where their head points to!!!
 
 
* Make the fish go up or down, slightly, randomly, as it moves forward...
 
  
 
<!-- /showafterdate -->
 
<!-- /showafterdate -->

Revision as of 08:29, 29 March 2015

--D. Thiebaut (talk) 07:14, 29 March 2015 (EDT)



Exceptions


Part 1: Preparation


  • Create a new program called lab9_1.py, and copy this code to the new Idle window.


# lab9_1.py
# Your name here

# getInput: returns an integer larger
# than 0.  Expected to be robust
def getInput():
   
   while  True:
      x = int( input( "Enter an integer greater than 0: " ) )
      if x <= 0:
         print( "Invalid entry.  Try again!" )
      else:   
         return x

def main():
   num = getInput()
   print( "You have entered", num )

main()
  • Test it with numbers such as -3, -10, 0, 5. Verify that the input function works well when you enter numbers.
  • Test your program again, and this time enter expressions such as "6.3", or "hello" (without the quotes).
  • Make a note of the Error reported by Python:


Lab9Exception1.png


  • Modify your function and add the highlighted code below by hand. This code will catch the ValueError exception.


# getInput: returns an integer larger
# than 0.  Catches Value errors
def getInput():
    
   # repeat forever...
   while  True:

      # try to get an int
      try:
          x = int( input( "Enter an integer greater than 0: " ) )
      except ValueError:
          # the user must have entered something other than an int
          print( "Invalid entry.  Not an integer.  Try again!" )
          continue

      # No errors caught.  See if the number is negative
      if x <= 0:
         print( "You entered a negative number.  Try again!" )
      else:   
         # finally, we can return x as it is an int that is >0
         return x


  • Run your program and try different invalid inputs, such as strings or floats. You can also try just pressing the Return key, indicating that you are not providing anything to the input function. Verify that your program catches all these invalid entries and does not crash.


Review Class Example


  • Below is an example we saw in class, and that is taken from Zelle. It illustrates how we can guard some code against several types of errors. Review it. You will need to follow this example for the next set of exercises.


def ZelleExample():
    import math
    print( "solution to quadratic equation" )
    try:
        a, b, c = eval( input( "enter 3 coefficients (a,b,c) " ) )
        disc = math.sqrt( b*b - 4*a*c )
        root1 = (-b + disc )/ (2*a)
        root2 = (+b + disc )/ (2*a)
        print( "solutions: ", root1, root2 )
    except NameError:
        print( "You didn't enter 3 numbers" )
    except TypeError:
        print( "Your inputs were not all numbers" )
    except SyntaxError:
        print( "Forgot commas between the numbers?" )
    except ValueError:
        print( "No real roots, negative discriminant" )
    except:
        print( "Something went wrong..." )


Part 2: Exercise


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


def example1():
    for i in range( 3 ):
        x = int( input( "enter an integer: " ) )
        y = int( input( "enter another integer: " ) )
        print( x, '/', y, '=', x/y )

def example2( L ):
    print( "\n\nExample 2" )
    sum = 0
    for i in range( len( L ) ):
        sum +=  L[i]

    print( "sum of items in ", L, "=", sum )


def printUpperFile( fileName ):
   file = open( fileName, "r" )
   for line in file:
       print( line.upper() )
   file.close()

def createTextFile( fileName ):
   file = open( fileName, "w" )
   file.write( "Welcome\nto\nCSC111\nIntroduction\nto\nComp.\nSci.\n" )
   file.close()

def main():
    # create a text file for use later...
    createTextFile( "csc111.txt" )

    # test first function
    example1()

    # test second function
    L = [ 10, 3, 5, 6, 9, 3 ]
    example2( L )
    #example2( [ 10, 3, 5, 6, "NA", 3 ] )

    # test third function 
    fileName = input( "Enter name of file to display (type csc111.txt): " )
    printUpperFile( fileName )

main()



  • The program above has many flaws; it is not very robust. We can easily make it crash.
  • Observe each function. Run your program a few times.
  • Figure out how to make each function crash
  • Go ahead and start forcing the first function to crash. Register the XXXXError that is generated. For example, if the output of the crash looks like this:

Traceback (most recent call last):
File "/Users/thiebaut/Desktop/except0.py", line 29, in <module>
main()
File "/Users/thiebaut/Desktop/except0.py", line 27, in main
example3( [ 10, 3, 5, 6 ] )
File "/Users/thiebaut/Desktop/except0.py", line 18, in example3
sum = sum + L[i]
IndexError: list index out of range

what you are interested in is IndexError. This is the exception you want to guard your code against.


  try:
      ........
      ........
  except IndexError:
      .........


  • Add the try/except statement inside the function, and verify that your function is now more robust and does not crash on the same input that made it crash before.


  • Repeat the same process for the other functions.


Classes and Objects


Fileicon-pdf.png
You may find the following document describing the different graphic objects introduce in the Zelle's textbook useful.


Classes for a wheel and a Car

Below is the code we wrote in class this week:

# carNew.py
# D. Thiebaut
# first program using a class to define                                                                               
# a new graphic object: a wheel, which                                                                
# is made of 2 concentric circles.  The class
# Wheel supports methods to initialize the
# graphics object, draw it on the window,
# and move it.

from graphics import *
W = 400    # width of the graphics window
H = 400    # height of the graphics window

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

    def __init__( self, center, r1, r2 ):
        """constructor"""
        self.radius1 = min( r1, r2 )
        self.radius2 = max( r1, r2 )
        self.circ1 = Circle( center, self.radius1 )
        self.circ2 = Circle( center, self.radius2 )
        
    def draw( self, win ):
        """draws the wheel on the graphics window win"""
        self.circ2.draw( win )
        self.circ1.draw( win )

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

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

    def getRadius1( self ):
        """returns the smallest radius"""
        return self.radius1

    def getRadius2( self ):
        """returns the largest radius"""
        return self.radius2

class Car:
    def __init__( self, P1, P2 ):
        self.body = Rectangle( P1, P2 )
        w =abs( P2.getX()-P1.getX() )
        h =abs( P2.getY()-P1.getY() )
        center1 = Point( w/4+P1.getX(), P2.getY() )
        center2 = Point( P2.getX()-w/4, P2.getY() )
        r2      = w/8
        r1      = r2/2
        self.w1 = Wheel( center1, r1, r2 )
        self.w2 = Wheel( center2, r1, r2 )

    def setFill( self, bodyc, tirec, insidec ):
        self.body.setFill( bodyc )
        self.w1.setFill( tirec, insidec )
        self.w2.setFill( tirec, insidec )

    def draw( self, win ):
        self.body.draw( win )
        self.w1.draw( win )
        self.w2.draw( win )

    def move( self, dx, dy):
        self.body.move( dx, dy )
        self.w1.move( dx, dy )
        self.w2.move( dx, dy )

#----------------------------------------------------------------
def waitForClick( win, message ):
    """ waitForClick: stops the GUI and displays a message.  
    Returns when the user clicks the window. The message is erased."""

    # wait for user to click mouse to start
    startMsg = Text( Point( win.getWidth()/2, win.getHeight()/2 ), message )
    startMsg.draw( win )    # display message
    win.getMouse()          # wait
    startMsg.undraw()       # erase


def main():
    """demo program for wheel: draws wheel on screen"""
    global W, H
    win = GraphWin( "wheel demo", W, H )
    waitForClick( win, "click to start" )

    #--- create new wheel object ---
    #w = Wheel( Point( W/2, H/2 ), 20, 40 )
    #w.setFill( "black", "yellow" )
    #w.draw( win )

    #--- create a car object ---
    car = Car( Point( 20, 20 ), Point( 120, 60 ) )
    car.setFill( "red", "yellow", "black" )
    car.draw( win )
    waitForClick( win, "click to move" )


    #--- move the car ---
    for i in range( 100 ):
        car.move( 3, 0 )

    waitForClick( win, "click to end" )

main()


  • Run the program a few times to make sure you understand how it works.
  • Assume that the programmer writing the main program (we always assume that the programmer writing the main program is different from the programmer writing the classes, as is most often the case in real life) forgot the rule that when building a car, the first point passed to the constructor is the top left point of the rectangle defining the body, and that the second point is the bottom right point of the body.
Instead the programmer creates the object car as follows:
   car = Car( Point( 120, 60 ), Point( 20, 20 ) )


Make this modification and run your program. What happens?
  • Fix the class Car so that the user can specify any point in any order (top-left, bottom-right), or (top-right, bottom-left), or (bottom-left, top-right), and the constructor will correctly define the body and the wheels to fit the shape defined by the two points.
  • Oh, by the way, the car is a two-door convertible. Add a door to the car. The door should be a simple rectangle in the middle of the body of the car, between the two wheels. (You may want to sketch the shape of the car on paper and figure out what proportions to use to position the door.)

Random cars going in random directions

  • Make your program create a list of 5 cars.
  • Each car has a random horizontal velocity (dx != 0, dy=0), making it go left, or right. Make dx and dy part of the class, i.e. make these variables member variables of the class Car.
  • Make your program move all 5 cars at the same time, until all the cars have exited the window. As soon as the cars all disappear your program will stop. Think of an efficient way to do this... This is a bit tricky... (But we are at a time in the semester where you can deal with tricky questions... :-)