Lecture 5 - Classes and Objects


As usual, create a directory to hold today's activities:

$ mkdir ~/cs170/labs/lab5
$ cd ~/cs170/labs/lab5

Quiz

No longer an announcement! You will find the quiz on Inquire. There is a 20 minute time limit, but it should not take near that long to complete!


Creating Classes (From Scratch)

On Monday, you saw how we can take something we had already written, and convert it into a class structure. This is not how we typically go about writing our classes. Instead, we would probably design and write our classes from the beginning, and just use them in our code. Today, you are going to write a class from scratch, using something that is hopefully fairly familiar to you.


Lab Assignment 5
Fractions

Today is the day that you create your first legitimate data type, and this time it is from scratch! One of the major complaints about the floating point data type is that it cannot represent every rational number. So, let's make a data type that can do that.

Details

Create a class called Fraction in a file called fractions.py. Your class should be able to represent arbitrary fractions. You should be able to add two fractions together, and multiply fractions. You should also be able to print fractions, so you can see the result of your work. Your code should only work for positive fractions.

Think about what attributes you need to represent a fraction. This should be decently straight forward, but if you need a refresher on fractions take a look at this web page.

Example

>>> fraction_1 = Fraction(1, 2)
>>> fraction_2 = Fraction(3, 4)
>>> result = fraction_1.add(fraction_2)
>>> print(fraction_1)
1/2
>>> print(fraction_2)
3/4
>>> print(result)
5/4
>>> result = fraction_2.multiply(fraction_1)
>>> print(result)
3/8

Hint

  • You are definitely going to need two attributes, one for the numerator, and another for the denominator.

  • Your operators should behave just like the operators do for other data types: They should not modify either of the current fractions. Instead, they should return a new fraction, which is the result of the operation.

  • Remember, you need to override the __str__ method, so you can just use the print function to print out your fractions.
  • Multiplication is easy, just multiply the numerators together, and the denominators together.

  • Your add function is going to have to compute a common denominator. The easiest way to accomplish this is by multiplying the two denominators together.

    This means you need to multiply the numerator of the current fraction by the other fractions denominator (and vice versa) to make sure the value of each fraction does not change. Then you just add the new numerators together.

  • If you have written your methods correctly, you should be able to override the built-in operators by simply changing the name of the methods to __add__ and __mul__:

          >>> result = fraction_1 + fraction_2
          >>> print(result)
          5/4
          >>> result = fraction_1 * fraction_2
          >>> print(result)
          3/8
          

 

Challenge

This Fraction class is not quite complete! It at least needs subtraction and division operations. You should be able to very easily add these two operations in, if you are sneaky about it.

Keep in mind that subtraction might result in negative fractions. It is fine to have negative fractions, but to get full functionality of a Fraction object, we need to make sure we handle that gracefully. See the next challenge for how to handle that.

 

Challenge

The way the fraction class is currently set up, you can easily get a fraction 2/4. This probably makes the math majors in the room cringe, but is technically a valid fraction. It just is not in its most reduced form.

Let's define the reduced form of a fraction as follows:

Write a function that converts the current fraction to its most reduced form. You can then fix all of your operators with one call to this new method.


Lab Assignment 4
Pong

If you have not completed Pong (the class version, without challenges), finish it up today. You will see the prompt below. If you have completed Pong, work on Sudoku. You can complete Pong with scores and game over conditions later.

Details

You are going to create two different classes for the Pong game: Ball and Paddle. The Ball class should contain all of the data and functionality required for create a ball that bounces around the screen. The Paddle class should contain all of the data and the functionality required to create a single paddle.

Notice that you are only writing a single Paddle class. Even though you only have one class, you can create multiple objects which are instances of the Paddle class. You should structure your Paddle class so that it can represent a Paddle at an arbitrary x location in the window.

You are also going to write all of your paddle event listeners in the Paddle class. However, you are only going to bind the once necessary for each player. This way, you can easily change which player is in control of which paddle, by simply changing which function gets bound when you run your program.

The Ball class should have an update function. This function should be responsible for moving the ball to its new location, as well as handling collisions with the walls and the paddles. You will have to call this function from your main loop.

Think about what values we have been using from the global namespace to represent these entities. You should be able to remove most of the global variables with this new setup.

Hint

  • Your Paddle constructor should take the starting_x location, the starting_y location, and the canvas the Paddle should be drawn on. These should be stored in class attributes , so they can be used in other methods within the Paddle class.

    You will also want to store the Id that gets returned from the create_rectangle method as an attribute of the class, so you can use it in your event handlers. You probably want to do the same thing with your Ball class as well.

  • Your current event handlers should just need to be copied and pasted into your Paddle class. You will need to update some of the variable identifiers, so they use the class attributes instead of pulling information out of the global namespace.

    When you bind the event handlers in the main portion of your program, you can simply do the following:

    paddle_1 = Paddle(PADDLE_1_STARTING_X, WINDOW_HEIGHT // 2,
                      canvas)
    canvas.bind("<B1-Motion>", paddle_1.handle_mouse_motion)
    paddle_2 = Paddle(PADDLE_2_STARTING_X, WINDOW_HEIGHT // 2,
                      canvas)
    canvas.bind("<Key>", paddle_2.handle_keys)
    

  • Your Ball constructor should take the same information as the paddle. You will also want to initialize attributes for the X and Y components of the ball's velocity.

  • Your Ball class should also have a method called detect_paddle_collision(self, paddle), which takes a reference to a paddle object. This function should return True if the ball's current location collides with the specified paddle.

  • The Ball class' update function should take a list of paddles which it needs to interact with. This is very important for use with detect_paddle_collision.


Submission

When you have finished, create a tar file of your lab5 directory. To create a tar file, execute the following commands:

cd ~/cs170/labs
tar czvf lab5.tgz lab5/

To submit your activity, go to cseval.roanoke.edu. You should see an available assignment called Lab Assignment 5. Make sure you include a header listing the authors of the file.


Class Notes


Last modified: Wed Jan 22 14:42:34 EST 2014