CS 240: Data Structures and Algorithms
James Madison University, Fall 2012

HW #3

For this assignment you will use Blackboard to submit a single .py file containing solutions to the following programming exercises. Your file should have header comments that include your name, the date, and your acknowledgments statement. Carefully test each function to make sure that it works as expected. These exercises will be graded both on functionality and code quality.

  1. Implement the class hierarchy described by the UML diagram below. (15pts)

    NOTES:
    • All draw methods should be implemented using turtle graphics.
    • Circles should be drawn centered on their position.
    • For Rectangles and Polygons, the shape's position corresponds to the lower-leftmost vertex. All Polygons should be drawn with a horizontal line at the bottom of the shape.
    • The contains method should return True when the tested point is contained in the shape or touching the boundary.
    • It is a little tricky to write the contains method for the polygon class. You need not fully implement that method. Instead, it should raise an exception of type NotImplementedError.
    • Each class and method should have an appropriate docstring.
    • When using turtle graphics, the position (0, 0) is at the center of the screen, and y-coordinates increase as one moves up the screen.
    • You do not need to describe preconditions, post-conditions, or class invariants for these classes. Nor do you need to use assertions to check for errors.
    • I will use (at least) the following method to test your code. Passing these tests does not prove that your code is correct, but failing any of these tests does demonstrate that you have a problem. (This is an ugly way of handling testing. We will see how to use a proper unit testing framework later in the semester.)
      def testShapeClasses():
          rect = Rectangle(0., 200., 50., 100., "blue")
          circ = Circle(0., 200., 40., "red")
          tri = Polygon(0., 200., 3, 40.,"black")
          
          print("Testing Accessor Methods-------------------------------------------")
          print("Rectangle, should see: 0., 200., 50, 100., blue")
          print("{0} {1} {2} {3} {4}".format(rect.xPos(), rect.yPos(), 
                                             rect.height(), rect.width(), 
                                             rect.color()))
          
          print("Circle, should see: 0., 200., 40, red")
          print("{0} {1} {2} {3}".format(circ.xPos(), circ.yPos(), 
                                         circ.radius(), circ.color()))
          
          print("Polygon, should see: 0., 200., 3, 40., black")
          print("{0} {1} {2} {3} {4}".format(tri.xPos(), tri.yPos(), 
                                         tri.numSides(), tri.sideLength(),
                                         tri.color()))
          
          print("\nTesting Contains Methods-----------------------------------------")
          
          print("(0,0) should not be in rectangle (False):")
          print(rect.contains(0.,0.))
          print("(20,210) should  be in rectangle (True):")
          print(rect.contains(20.,210.)) 
      
          print("(0,0) should not be in circle (False):")
          print(circ.contains(0.,0.))
          print("(0,200) should  be in circle (True):")
          print(circ.contains(0.,200.)) 
          
          try:
              tri.contains(0., 0.)
              print ("ERROR, exception should have been raised.")
          except NotImplementedError:
              print ("Polygon contains NotImplemented exception successfully raised.")
          
          print("\nTesting __str__ methods, should display three shapes as strings:-----")
          print(rect)
          print(circ)
          print(tri)
          
          print("\nTesting draw methods---------------------------------------------")
          rect.draw()
          circ.draw()
          tri.draw()
          turtle.exitonclick()    
      
      The result of the draw commands should look something like the following:
  2. Rename the drawPolygons function from HW#2 to drawShapes and rewrite it so that it takes a list of Shape objects as an argument. (The code should be simpler than the previous version.) Don't forget to update the docstring appropriately. List the preconditions for this function and use assertions to test them. (5pts)
  3. Write a function named readShapeFile that takes a filename as an argument, and returns a list of shapes. Each line in a correctly formatted file will specify a single shape object:
    • For Rectangles the format is an "r" followed by the X position, Y Position, height, width and color.
    • For polygons the format is a "p" followed by the X position, Y Position, the number of sides, the side length and the color.
    • For circles the format is a "c" followed by the X position, Y Position, the radius and the color.
    A complete file (corresponding to the shapes from the test above) might look like the following:
    r 0.0 200.0 50.0 100.0 blue
    c 0.0 200.0 40.0 red
    p 0.0 200.0 3 40.0 black
    
    Also, create a user-defined exception class named FileFormatError. Your new function should raise a FileFormatError if the file format is not correct. (5pts)