Python Exercises lab 6

6.1 Prerequisites and learning outcomes

Before you start you are expected to have completed lab 5.

At the end of this lab you will have:

6.2 Creating and testing a simple class

a. In a Python script file called round.py create a circle class. This should have a constructor method which stores the radius of a circle object as self.radius . This class should have 2 further methods:

b. Test your class by importing your round module and creating 2 circle objects with different radiuses.

c. Using the methods, print the areas and circumferences of both circle objects.

d. print your source code and test results and put these into your logbook.

6.3 Subclassing an existing class

a. Download ballBox.py and balls.py into the same folder. Inspect balls.py and inspect and run ballBox.py . This should bring up a GUI application with 3 buttons. Experiment with this application and write down in in your logbook what happens when each button is pressed. Do all of the balls fall at the same speed ? What in real life might cause balls to fall at different speeds ? Write your observations into your logbook.

b. balls.py contains a class called Ball. Objects of this class hold certain information about a ball. Inspect the code for this class and write down in your logbook which object attributes are stored in an object of the ball class. Write down what the methods do.

c. Inspect the drop() method carefully. Try commenting out the statement which tests for a remainder and the 4 lines of code in the block controlled by this test. Save this modified file. Exit and restart the PythonWin environment and re-run ballBox.py and observe the change . How did the original application decide on the number of steps and why was there a difference between the intended drop and the size of step times the number of steps calculated ? Write down in your logbook what the remainder test and block did within the drop() method.

d. Restore the commented out lines of code in the drop() method and reload the class (you may need to restart PythonWin again) so that the balls drop the whole distance again.

e. You are now asked to create Python source code for a subclass of the Ball class called BounceBall. You will only need to change the drop() method of your subclass to make the ball bounce when it gets to the bottom of its travel. Examples of a compiled Python module: balls2.pyc which does this and a modified ballBox2.py source file which runs the compiled file are available. (balls2.pyc doesn't contain Python source code, this is in a binary compiled Python bytecode format.)

Hints:

i. It is suggested that your subclass is given a bounce coefficient of -0.8 or so to multiply the y speed by when the ball hits the bottom of the box, to simulate the effect of a ball bouncing. Reversing the speed by multiplying by a number between -0.5 and -0.95 is very similar to what a real ball does when it doesn't bounce quite as high on the next bounce as it did on the last one. -0.5 probably wouldn't look bouncy enough but -0.95 would probably go on bouncing too long for productive software testing and not look realistic.

ii. You might consider increasing the y speed by 0.2 or so every move to simulate the effect of gravity. When the ball is falling y speed will increase, and when it is rising (negative) y speed will be reduced because gravity always works in the same direction.

iii. You will probably have to do your calculations of ball position and speed using floats. You can translate from integer to float using the float() function. You can translate back to integer from float to update the canvas using the int() function. It is suggested that you copy the initial value of the self.y_speed (integer) Ball object attribute to a local (float) variable within the drop() method to do your speed and distance computations for each step. Update the self.y integer attribute to update the canvas based on the distance between this and the self.y attribute on the previous step. However, store the position ready for calculating the next move using a more accurate float variable, and so the float to int rounding difference between the computed and drawn positions of the ball will always be less than 1 pixel.

iv. When you detect the need to bounce (ball hits bottom of box) it is suggested that you adjust the ball position to ground it exactly on the bottom before reversing its y speed. You reverse the y speed by multiplying the previous y speed by the bounce coefficient. You may need to "ground" the ball every time it bounces to avoid the ball appearing to drift downwards as it slows down towards its last bounces.

v. You will need to decide when to stop your method. It is suggested that you loop ball moves a maximum of say 400 steps to avoid an infinite loop while testing neater loop termination conditions. A good loop termination condition is when the ball is within 0.2 pixels of the bottom and is travelling at an absolute (i.e. positive or negative) y speed of less than 0.2 pixels per move.

vi. You only need a small change to 1 line of ballBox.py to make it construct your new BounceBall class instead of its parent Ball class, see ballBox2.py for details.