Difference between revisions of "CSC111 Lab 10 2010"

From dftwiki3
Jump to: navigation, search
(Fish)
m (Thiebaut moved page CSC111 Lab 10 to CSC111 Lab 10 2010)
 
(17 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
{|
 +
| width="40%" |
 +
__TOC__
 +
|
 
<bluebox>
 
<bluebox>
<br>
 
 
This lab deals with classes, objects, and graphics.  It builds on the examples we saw in class on Monday and Wednesday.
 
This lab deals with classes, objects, and graphics.  It builds on the examples we saw in class on Monday and Wednesday.
 
<br>
 
<br>
 
</bluebox>
 
</bluebox>
 
+
|}
  
 
<br />
 
<br />
Line 12: Line 15:
 
</tanbox>
 
</tanbox>
 
<br />
 
<br />
==A class for a wheel==
+
==Classes for a wheel and a Car==
  
 
Below is the code we wrote in class yesterday:
 
Below is the code we wrote in class yesterday:
  
 
<source lang="python">
 
<source lang="python">
      # lab10_1
+
# carNew.py
      # A program incorporating a class for a wheel
+
# D. Thiebaut
      # which can move freely on the screen
+
# 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 *
+
from graphics import *
      WinXBR = 700    # window geometry
+
W = 400
      WinYBR = 500
+
H = 400
  
 +
#----------------------------------------------------------------
 +
class Wheel:
 +
    """A class with two concentric circles"""
  
      #----------------------------------------------------------------
+
    def __init__( self, center, r1, r2 ):
      # Wheel class
+
        """constructor"""
      #----------------------------------------------------------------
+
        self.radius1 = min( r1, r2 )
      class Wheel:
+
        self.radius2 = max( r1, r2 )
          """A wheel is two concentric circles that move as one unit"""
+
        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 __init__( self, c, rs, rb ):
+
    def move( self, dx, dy ):
              """constructor. Gets the center, the small radius and the large radius"""
+
        self.circ1.move( dx, dy )
              self.bigCircle  = Circle( c, rb )
+
        self.circ2.move( dx, dy )
              self.smallCircle = Circle( c, rs )
 
  
          def move( self, dx, dy ):
+
    def setFill( self, color1, color2 ):
              """moves the wheel by dx horizontally and dy vertically"""
+
        self.circ1.setFill( color1 )
              self.bigCircle.move( dx, dy )
+
        self.circ2.setFill( color2 )
              self.smallCircle.move( dx, dy )
 
  
          def draw( self, win ):
+
    def getRadius1( self ):
              """draws the circles on the window"""
+
        """returns the smallest radius"""
              self.bigCircle.draw( win )
+
        return self.radius1
              self.smallCircle.draw( win )
 
  
      #----------------------------------------------------------------
+
    def getRadius2( self ):
      # waitForClick: stops the GUI and displays a message. 
+
        """returns the largest radius"""
      #----------------------------------------------------------------
+
        return self.radius2
      def waitForClick( win, message ):
 
          # wait for user to click mouse to start
 
          startMsg = Text( Point( WinXBR/2, WinYBR/2 ), message )
 
          startMsg.draw( win )    # display message
 
          win.getMouse()          # wait
 
          startMsg.undraw()      # erase
 
  
 +
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 )
      def main():
+
        self.w1.setFill( tirec, insidec )
          win = GraphWin( "Demo: Wheeling Around", WinXBR, WinYBR  )
+
        self.w2.setFill( tirec, insidec )
          waitForClick( win, "Click mouse to start" )
 
         
 
          #--- create a wheel ---
 
          w = Wheel( Point( 30, 50 ), 25, 30 )
 
          w.draw( win )
 
             
 
          waitForClick( win, "Click mouse to stop" )
 
          win.close()
 
  
      main()
+
    def draw( self, win ):
</source>
+
        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 )
  
* Run the program.
+
#----------------------------------------------------------------
 +
def waitForClick( win, message ):
 +
    """ waitForClick: stops the GUI and displays a message.
 +
    Returns when the user clicks the window. The message is erased."""
  
* Add a loop that will make the wheel move by 400 steps, horizontally.
+
    # 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
  
* Add a method to set the color of the wheel. This method will receive two colors, and set the color of the inside circle with the first color passed, and the color of the outside circle with the second color passed. Just look at how the methods of the class Wheel work to figure out how to write the setFill() method. It has to be logical. This is new syntax for us, so don't hesitate to ask for help if you aren't sure...
 
  
* Test the setFill() method.
+
def main():
 +
    """demo program for wheel: draws wheel on screen"""
 +
    global W, H
 +
    win = GraphWin( "wheel demo", W, H )
 +
    waitForClick( win, "click to start" )
  
* How does your program work if the user specifies the larger radius first in the constructor?  For example, replace the creation of the '''w''' object with this statement:
+
    #--- create new wheel object ---
 +
    #w = Wheel( Point( W/2, H/2 ), 20, 40 )
 +
    #w.setFill( "black", "yellow" )
 +
    #w.draw( win )
  
      w = Wheel( Point( 30, 50 ), 30, 25 )
+
    car = Car( Point( 20, 20 ), Point( 120, 60 ) )
 +
    car.setFill( "red", "yellow", "black" )
 +
    car.draw( win )
 +
    waitForClick( win, "click to move" )
  
:What happens with the colors? 
 
  
* Modify the class so that it swaps the radii around if the user does not specify them in the correct order.
+
    #--- move the wheel ---
 +
    for i in range( 100 ):
 +
        car.move( 3, 0 )
  
* The Circle, Rectangle, Line and other objects supported by the graphics library all have an '''undraw()''' method, that does take no parameters.  Add an '''undraw()''' method to your Wheel class.
+
    waitForClick( win, "click to end" )
  
* The wheel is very close to a circle. In fact it's a circle with a smaller circle inside, so some of the methods that apply only to circles should probably be added our wheel class.
+
main()
** getCenter()
 
** getRadius()  
 
  
: These are different from the others: they return values. Start with getRadius() first. Make it return the radius of the larger circle.
 
  
     
+
</source>
: The getCenter() method of the Circle returns a point. Your method should return a point too. In fact, it is a simple method: it will return the point returned by the getCenter() method of any of the two circles... Think about it...
 
  
   
 
* Test your method with the python statements below... They will energize all your methods:
 
  
          w = Wheel( Point( 30,30 ), 20, 25 )
+
* Run the program a few times to make sure you understand how it works.
          w.draw( win )
 
          waitForClick( win, "click to color" )   
 
          w.setFill( "orange", "black" )
 
          waitForClick( win, "click to hide" )
 
          w.undraw()
 
          waitForClick( win, "click to bring back" )
 
          w.draw( win )
 
          waitForClick( win, "click to get coordinates of wheel" )
 
          p = w.getCenter()
 
          x = p.getX()
 
          y = p.getY()
 
          waitForClick( win, "center of wheel is at (%d, %d)" % ( x, y ) )
 
          r = w.getRadius()
 
          waitForClick( win, "radius of the wheel is %d" % ( r ) )
 
  
==A class for a car==
+
* 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.
  
Rather than telling you how to create the class for a car, try to figure it out by seeing how car objects are used in the simple example below. All you need to know is that a car contains 3 objects: two wheels, and a rectangle, which is horizontal, and whose two bottom corners correspond to the centers of the wheels. Only the outside radius of the wheel is specified. The inside radius is taken to be 60% the size of the outside radius.
+
:Instead the programmer creates the object '''car''' as follows:
  
Car is the class, and car1 the object.
+
    car = Car( Point( 120, 60 ), Point( 20, 20 ) )
  
<source lang="python">
 
  
          # create a car, first wheel centered at 30,30, 2nd wheel
+
:Make this modification and run your program.  What happens?
          # at 90,30, both wheels with a radius of 20, and the
+
 
          # rectangle with a height of 40.
+
* 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.
          car1 = Car( Point( 30, 30 ), 20, Point( 90,30 ), 20, 40 )
 
          car1.draw( win )
 
  
          # color the wheels grey with black tires, and the rectangle yellow
+
* 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.)
          car1.setFill( "black", "grey", "yellow" )
 
  
          # make the car move on the screen   
+
* Add a windshield to the car as well.  You are free to define its shape, and the '''Polygon''' class will provide a nice solution for you.  '''Polygons''' are defined in Section 3.6 of [http://cs.smith.edu/dftwiki/images/1/17/ZelleGraphicsDescription.pdf Zelle's 4-page document on his graphics library].
          for i in range( 400 ):
 
              car1.move( 1, 0 )
 
             
 
</source>
 
  
 
==Random cars going in random directions==
 
==Random cars going in random directions==
Line 148: Line 154:
 
* 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, making it go left, or right.
+
* 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'''.
  
* 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.
+
* 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==
 
==Fish==
  
* get a copy of the file allfish.tgz (available [[media:allfish.tgz| here]] as well):
+
This section is reported to [[CSC111 Lab 11| Lab 11]]...
  
  getcopy allfish.tgz
+
* Point your browser to http://maven.smith.edu/~111c/index.html
  
* then unpack it
+
* See all the fish?  Make a note of one of the fish, and get a copy of its file as follows
  
  tar -xzvf allfish.tgz
+
  getcopy fishxx.gif            ''(replace xx by the actual number of the fish you want)''
  
* Take a look at what is in your directory:
+
* Write a new graphics program and copy/paste the following code in it:
 +
<br />
  
  ls
+
<source lang="python">
 
+
.
:See all the fish files there? 
 
 
 
* You are going to create a Web page with a picture of all of them, just so that you can see what they look like.
 
  
* Copy all the fish files to your '''public_html''' directory.  This is the directory where you can store Web pages that will be visible on the Web.
+
from graphics import *
 +
H = 400
 +
W = 400
  
  cp fish*.gif public_html
+
def waitForClick( win, message ):
 +
    """ waitForClick: stops the GUI and displays a message.
 +
    Returns when the user clicks the window. The message is erased."""
  
* go to your public_html directory
+
    # 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
  
  cd public_html
 
  
* list all the fish files:
+
def main():
 +
    global H, W
 +
    win = GraphWin( "Fish Tank", W, H )
 +
    waitForClick( win, "click to start" )
  
  ls -1                      (''that's ell ess space minus one'')
+
    fish = Image( Point( W/2, H/2 ), "fish15.gif" )  # replace 15 by the number of your fish
 +
    fish.draw( win )
  
* save the list in a file, which will become a python program
+
    waitForClick( win, "click to end" )
 +
    win.close()
  
  ls -1  >  generateWebPage.py
+
main()
  
* emacs the file '''generateWebpage.py''' and add the following code around your list of fish files:
 
 
<source lang="python">
 
text = """
 
 
   
 
   
  (put the list of fishXX.gif in this string, one per line, as it appears in the file)
+
.
 
 
 
 
"""
 
print "<html><body><h1>Fish in need of an aquarium...</h1><ul>"
 
for fish in text.split( "\n" ):
 
    fish = fish[:-1] # remove the '*' at the end of the file
 
    print "<hr><li> %s <img src=\"%s\">" % ( fish, fish )
 
print "</ul></body></html>"
 
 
</source>
 
</source>
  
* Run the program once
+
* Add a for loop and make the object ''fish'' move by dx, dy some fixed number of steps...
  
  python generateWebPage.py
+
* Create a an new class which is a fish, with its own file name, and its own dx and dy.
  
* Verify that it generates a list of html statements
+
* Create an object issued from the class.  Verify that you can make the object move on the screen.
  
* Now run the program again, but make it store the output into a file which will become a Web page:
+
* 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!!!
  
  python generateWebPage.py  > index.html
+
* Make the fish go up or down, slightly, randomly, as it moves forward...
  
* Point your browser to http://cs.smith.edu/~111c-xx/index.html  (''replace '''xx''' by your 2-letter Id'') and verify that you get a collection of pictures of fish.
+
<br />
 
+
<br />
:Now you know what they look like! :-)
+
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
[[Category:CSC111]][[Category:Labs]][[Category:Python]]

Latest revision as of 06:53, 29 March 2015

This lab deals with classes, objects, and graphics. It builds on the examples we saw in class on Monday and Wednesday.


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 yesterday:

# 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
H = 400

#----------------------------------------------------------------
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 )

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


    #--- move the wheel ---
    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 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 (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... :-)

Fish

This section is reported to Lab 11...

  • 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:


.

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()

 
.
  • 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...