Python is an object-oriented language.
This means, not only can we use objects, but we can define our own
classes of objects. A class is just another name for a type in
Python. We have been working with types (i.e. classes) since the
first chapter of the text. Examples of classes are int, str, bool, float and list. While these classes are all built
in to Python so we can solve problems involving these types,
sometimes it is nice if we can solve a problem where a different
type or class would be helpful.
Classes provide us with a powerful tool
for abstraction. Abstraction is when we forget about details of how
something works and just concentrate on using it. This idea makes
programming possible. There are many abstractions that are used in
this text without worrying about exactly how they are implemented.
For example, a file is an abstraction. So is a list. In fact,
integers are abstractions, too. A turtle is an abstraction that
helps us implement Turtle graphics programs. Instead of worrying
about how a line gets drawn in a window, we can just move the
turtle along the line with its pen down to draw the line. How is
this done? It’s not important to us when we are using a Turtle. We
just know it works.
So, classes are a
great tool for programmers because when a programmer uses a class
they don’t have to worry about the details. But, sometimes we might
be able to save time and implement a class that could be useful to
us and maybe to someone else as well. When we use a class we don’t
worry about the details of how an object works. When we implement a
class we must first decide what the abstraction is going to look
like to the user of it and then we must think about how to provide
the right methods to implement the abstraction. When defining or
implementing a class, the user is either yourself or another
programmer that is going to use the class when they create some
objects of the class you defined.
Classes provide the definitions for
objects. The int class
defines what integers look like and how they behave in Python. The
Turtle class defines what a
turtle looks like and all the methods that control its behavior. In
general, a class defines what objects of its type look like and how
they behave. We all know what an integer looks like. Its behavior
is the operations we can perform on it. For instance we might want
to be able to add two integers together, print an integer, and so
on. When we define our own classes we do two things.

Fig.
7.1
A Turtle object
-
A Class defines one or more data items to be included in the objects or instances of the class. These data items are sometimes called the member data or instance variables of the class. Each instance, or object, will contain the data defined by the class.
-
A Class defines the methods that operate on the data items or member data in objects of the class. The methods are functions which are given an object. A method defines a particular behavior for an object.
To understand how objects are created
we can look at an example. In Chap. 4 we learned how to create Turtle
objects and use them to do write some interesting programs.
Example
7.1
When we execute the code below, Python
creates a Turtle object pointed to by the reference t as shown in Fig. 7.1.

We have already learned that we could
make the turtle go forward 50 units by writing turtle.forward (50). The forward function is a method on a
Turtle. It is part of the turtle object’s behavior. As another
example, consider a Circle class. A circle must be drawn on the
screen at a particular location. It must be given a radius. It
might have a fill color and it might have a width and color for its
outline.
7.1 Creating an Object
When an object is created there are
two things that must happen: the space or memory of the object must
be reserved, and the space must be initialized by storing some
values within the object that make sense for a newly created
object. Python takes care of reserving the appropriate amount of
space for us when we create an object. We must write some code to
initialize the space within the object with reasonable values. What
are reasonable values? This depends on the program we are writing.

Fig.
7.2
A circle object
Example
7.2
To create a circle we might write
something like this.

Creating a circle called shape creates an object that contains
the data that we give the constructor when the circle is created.
The constructor is called when we write the class name, followed by
the arguments to pass to the constructor. In this case, the call to
the constructor is Circle (x, y, radius, width=3, color=“red”,
outline=“gray”). The constructor takes care of putting the
given information in the object. Figure 7.2 shows what the data
looks like in the object after calling the constructor.
The data in an object doesn’t get
filled in by magic. We must write some code to do this. When
programming in an object-oriented language like Python we can write
a class definition once and
it can be used to create as many objects of that class as we want.
To help us do this, Python creates a special reference called
self that always points to
the object we are currently working with. In this way, inside the
class, instead of writing the reference shape we can write the reference
self. By using the
reference self when writing
the code for the class, the code will work with any object we
create, not just the one that shape refers to. We are not stuck just
creating one circle object because Python creates the special
self reference for us. We
can create a shape and any
other circle we care to create by writing just one Circle
class.
Example
7.3
The first method of a class definition
is called the constructor
and is named __init__. It
takes care of filling in the member data inside the object. The
self reference is the extra
reference, provided by Python, that points to the current object.
This method gets called in response to creating an object as occurs
in the code in Example 7.2.

In Example 7.3 notice that the
formal parameters nearly match the arguments provided when the
circle object is created in Example 7.2. The one additional
parameter is the extra self
parameter provided by Python. When the constructor is called,
Python makes a new self
local variable for the __init__ function call. This
self variable points at the
newly created space for the object. Figure 7.3 shows the run-time
stack with the self
variable pointing at the newly created object. The picture shows
what memory looks like just before returning from the __init__ constructor method. There are
two activation records on the run-time stack. The first is the
activation record for the function that creates the shape by
executing the code in Example 7.2. The second
activation record is for the __init__ function call (i.e. the call
to the constructor). When the program returns from the constructor
the top activation record will be popped and the self reference will go away.

Fig.
7.3
A circle object
To implement a
class we must write the word class, the name of the class, and then
the methods that will operate on the objects of that class. By
convention, the first method is always the constructor. Generally
other methods follow and must be indented under the class
definition. The class definition ends when the indentation under it
ends.
Practice
7.1
Decide what information you would need
to implement a Rational class. Rational numbers are numbers that
can be expressed as a fraction with an integer numerator and
denominator. Then write a class definition for it including a
constructor so you can create Rational objects.
Practice
7.2
Assume we want to implement a class
for rectangles. A rectangle is created at a particular (x, y)
location specifying the lower left corner of the rectangle. A
rectangle has a width and height. Write a class definition for the
Rectangle class so that a rectangle can be created by writing
box =
Rectangle(100, 100, 50,
30) to create a rectangle at (100, 100) with a width of 50
and a height of 30.
If we have a circle object, it would
be nice to draw it on a turtle graphics screen. In addition, we may
want to change its color, width, or outline color at some point.
These are all actions that we want to perform on a circle object
and because they change the object in some way they will become
mutator methods when implemented. In addition, we may want to
access the x, y, and radius values. These are implemented with
accessor methods. The mutator and accessor methods must be defined
in the class definition.
Example
7.4
Here is the complete code for the
Circle class.

When a method is called on an object
the variable is written first, followed by a dot (i.e. period),
followed by the method name. So, for instance, to call the
getX method on the
shape you would write
shape.getX(). When you look
at the definition of getX
there is one parameter, the self parameter. When you call getX it looks like there are no
parameters. Python sets self to point to the same object that
appears on the left side of the dot. So, in this example, the
self parameter points at
the shape object because
shape was written on the
left hand side of the dot. The picture in Fig. 7.3 applies to calling the
getX method as well. When
getX is called, an
activation record is added to the stack with the self variable pointing at the object.
This is true of all classes in Python. When implementing a class
the first parameter to all the methods is always self and the object that is on the left
hand side of the dot when the method is called is the object that
becomes self while executing the method.
Practice
7.3
Complete the Rectangle class by
writing a draw method that
draws the rectangle on the screen. When drawing a rectangle allow
the color of the border and the color of the background to be
specified. Specify these parameters with default values of black
and transparent respectively. Make these parameters keyword
parameters with the names outline and color (for background color).
7.2 Inheritance
A class is an abstraction that helps
programmers reuse code. Code reuse is important because it frees us
to solve interesting problems while allowing us to forget the
details of the classes we use to solve a problem. Code reuse can be
achieved between classes as well. When objects are similar in most
respects but one is a special case of another the relationship
between the classes can be modeled using inheritance. A
subclass inherits from a
superclass . When using
inheritance, the subclass gets everything that’s in the superclass.
All data and methods that were a part of the superclass are
available in the subclass. The subclass can then add additional
data or methods and it can redefine existing methods in the
superclass.
Inheritance in Computer Science is
like inheritance in genetics. We inherit certain physical
characteristics of our birth parents. We may look different from
them but typically there are some similarities in hair color, eye
color, height and so on. We probably also inherit behaviors from
our parents, although this may come from social contact with our
parents and isn’t necessarily genetic. Inheritance when applied to
Computer Science means that we don’t have to rewrite all the code
of the superclass. We can just use it in the subclass.
Inheritance comes up all over the
place in OOP. For instance, the Turtle class inherits from the
RawTurtle class. The Turtle class is essentially a RawTurtle except
that a Turtle creates a TurtleScreen object if one has not already
been created.
Example
7.5
Here is the entire Turtle class.

While the code in
Example 7.5 is difficult to completely understand out
of context, the Turtle class only consists of a constructor, the
minimum amount that can be provided in a derived class. The
constructor creates the screen if needed and then calls the
RawTurtle’s constructor. Every class, whether a derived class or a
base class, must provide
its own constructor. When Python creates an object of a certain
class, it needs the constructor to determine how the object is
initialized. So, the class Turtle in Example 7.5 truly contains the
minimal amount of methods possible for a derived class.
Essentially a Turtle and a RawTurtle
are identical. It also turns out that Turtles (and RawTurtles) are
based on Tkinter. A TurtleScreen contains a ScolledCanvas widget
from Tkinter. To create a RawTurtle object we must provide a
ScrolledCanvas for the Turtle to draw on.
Example
7.6
Here is the constructor definition for
a RawTurtle.

Because turtle graphics is based on
Tkinter, we can write a program that contains widgets including a
canvas on which we can draw with turtle graphics! The constructor
in Example 7.6 shows us that if we provide a canvas the
RawTurtle object will use it. So, we could write a little drawing
program that draws circles and rectangles on the screen and
integrates other Tk widgets, like buttons for instance.
To begin building a draw application
we’ll put a ScrolledCanvas on the left side of a window and some
buttons to control drawing on the right side. Since we’ve been
looking at a Circle class, we’ll start by drawing circles on the
screen. It would be nice to provide the radius for the circle. We
can do that with an entry field and a StringVar object as was seen
in the last chapter.

Fig.
7.4
A drawing application
Example
7.7
Here is some code that creates a
ScrolledCanvas widget, a RawTurtle that draws on the canvas, and a
Tkinter application that incorporates both.
Figure 7.4 shows what the application window looks like
when it is run. Notice the use of the class definition for
DrawApp. Encapsulating all
the tkinter application code in a class means that self can be used to store variables
that need to be globally available to the application. In
particular, the shapeSelection variable in the object
is used and set in multiple places in the class. The main function
simply creates a DrawApp
object and then calls mainloop to make the tkinter
application start listening for events.

The program in
Example 7.7 is missing the Circle class which was defined in
Example 7.4. The program waits for the Circle button to be pressed once. Then,
after each mouse click, a circle is drawn on the ScrolledCanvas on
the left side of the window.
Both a Circle and a Rectangle share a
lot of common code. It makes sense for that common code to be in
one base class that both classes inherit from. If a Shape class
were defined that contained the shared code, then it would only
have to be written once, which is a requirement of elegant
code.
Example
7.8
Here is a Shape class that defines the
code that is common to both Circles and Rectangles.

With the Shape base class defined in
Example 7.8 the definition of Circle can be
simplified.
Example
7.9
Here is the code for the derived
Circle class. Notice the call to super() below. Super refers to the superclass, in this
case the Shape class. The
superclass is the class that is above it in the type hierarchy.
Using super() when
referring to the superclass is a good idea because the code still
works even if the type hierarchy is changed at some point in the
future.

The Circle class still is the only
class that will know how to draw a circle. And, of course, shapes
don’t have a radius in general. All the other code that isn’t
circle specific is now moved out of the Circle class.
Practice
7.4
Rewrite the Rectangle class so it
inherits from the Shape class and use it in the draw program
downloaded from the text’s website.
7.3 A Bouncing Ball Example
A RawTurtle can move around the screen
either with its pen up or its pen down. With its pen up, if we can
imagine the turtle as something other than a little sprite, it can
be essentially any object that we want it to be in a two
dimensional world. The creators of the turtle graphics for Python
realized this and added code so that we could change the turtle’s
picture to anything we would like. For instance, we might want to
animate a bouncing ball. We can replace the turtle’s sprite with an
image of a ball.
Turtle graphics can do animation
because it can be told to perform an action after an interval of
time. A timer can be set in turtle graphics. When the timer goes
off, the program can move the ball a little bit. If the interval
between timer going off and moving the ball can be small enough
that it happens several times a second, then to the human eye it
will appear as if the ball is flying through the air.
A ball is a turtle. However, a turtle
doesn’t remember in which direction it is moving. It would be nice
to have the ball remember the direction it is moving. At least
somewhere in the program the ball’s direction must be remembered
and it makes sense for the ball to remember its own direction in an
object-oriented design of the problem. Figure 7.5 depicts what a ball
object should look like. A ball is a turtle, but it is a little
more than just a turtle. Again, this is an example of
inheritance.
With the ball inheriting from the
RawTurtle class we’ll automatically get all the functionality of a
turtle. We can tell a ball to goto a location on the screen. We can
access the x and y coordinate of the ball by calling the
xcor and ycor methods. We can even change its
shape so it looks like a ball. As we’ve seen, for the Ball class to
inherit from the RawTurtle class, the derived Ball class must
implement its own constructor and call the constructor of the base
class.

Fig.
7.5
A ball object
Example
7.10
In Chap. 16 the Ball class inherits from the
RawTurtle class. To create a Ball object we could write

This creates a ball object as shown in
Fig. 7.5.
Here is the Ball class code.

When we are using the ball object in
Fig. 7.5
we refer to it using the ball reference. When we are in the Ball
class we refer to the object using the self reference as described earlier in
this chapter. In Fig. 7.5 the Turtle part of the object is greyed out.
This is because the insides of the RawTurtle are available to us,
but generally it is a bad idea to access the RawTurtle part of the
object directly. Instead, we can use methods to access the
RawTurtle part of the object when needed.
The constructor needs to initialize
the RawTurtle part of the object as well as the Ball part of the
object. To create a RawTurtle we could write turtle = RawTurtle(cv). However, writing this won’t work
to initialize the RawTurtle part of the object. A line of code like
this would create a new RawTurtle object. Remember, a Ball is a
RawTurtle so we don’t want to create a new RawTurtle object.
Instead, we want to initialize the RawTurtle part of the Ball
object. To do this, we explicitly call the RawTurtle constructor by
writing RawTurtle.__init__(self,cv). This calls the RawTurtle’s
constructor. In this case we call the constructor by writing the
class name followed by a dot followed by the constructor’s name
__init__. Since self is a
Ball and a RawTurtle, we
pass self as the parameter to RawTurtle’s constructor. This line of
code initializes the RawTurtle part of the object. Then the Ball
specific initialization occurs next.
The Ball class contains one more
method, the move method. This is a new method not defined in the
RawTurtle class. A Ball can move on the screen while a RawTurtle
can not. A Ball moves by (dx,dy) each time the move method is
called. The bouncing balls are animated by repeatedly calling the
move method on each of the balls in the ballList defined in the main function
of the program. Chapter 16 contains the complete code for the
bouncing ball example.
7.4 Polymorphism
Polymorphism is a term used in
object-oriented programming that means “many versions” or more than
one version. When a subclass defines its own version of a method
then the right version, either the subclass version or the base
class version of the method, will be called depending on the type
of object you have created. To best understand this it helps to
look at an example.
Let’s assume we wanted to modify the
bouncing ball example so some balls bounce according to a simulated
gravity instead of simply bouncing in space forever. It turns out
this is very easy to do. We can have Ball objects bounce in space
forever and GravityBall objects bounce according to a simulated
gravity. Since GravityBalls are nearly the same as Balls we’ll use
inheritance to define the GravityBall class. The only real
difference will be in the way the GravityBall moves when it is told
to move.
Example
7.11
This code uses the Ball class and
relies on polymorphism to get GravityBalls to bounce the right way.

Practice
7.5
Take the bouncing ball example and add
the GravityBall class to it. Then, modify the program to create
some GravityBalls and watch them bounce. The original Ball objects
continue to bounce around as if they were in space. The GravityBall
objects behave differently. Polymorphism makes this work. What is
it about polymorphism that makes this work the way we want it
to?
7.5 Getting Hooked on Python
A hook is a means by which one program
allows another program to modify its behavior. The Python
interpreter is a program that allows its behavior to be altered by
means of certain hooks it makes available to programmers. Consider
the Rational class described earlier in this chapter. With the
definition you came up with (or the provided solution in practice
Problem 7.1)
we can create Rational numbers. However, we can’t do much more than
create them at the moment. Without some more code, our rational
implementation doesn’t really do us much good.
Example
7.12
Here is some code that creates a
Rational number and prints it to the screen. When run, this program
prints something like
It prints the name of the module and
the class and the value of the reference when printed to the
screen.


If we needed
rational numbers in a program, it would be nice if they printed
nicely when they were printed to the screen. This can be done using
a hook in Python for string conversion. When an object is converted
to a string, Python looks for the existence of the __str__ method in the class. If this
method exists, Python will use it to convert the object to a string
representation. If this method exists in the class, then it must
return a string representation of the object. The method must also
have only one parameter, the self parameter.
Example
7.13
If this method is added to the
Rational class definition in Example 7.12, then when the
Rational
is printed, it prints as
.



The addition of the __str__ to the Rational class makes
using rational numbers a bit easier because we can quickly convert
it to a string when we want a nice representation of it. You can
force the __str__ method to
be called by calling the str built-in function in Python. So,
writing str(x) will force a string version of
x to be constructed using
the __str__ method. The
presence of the __str__
method doesn’t mean that rational numbers will always be converted to a string when
printed. Sometimes, the Python interpreter isn’t interested in
producing a strictly human-readable presentation of an object.
Sometimes a Python readable representation is more
appropriate.
Example
7.14
Consider the following code. When
Rational objects are in a list they do not print using
the __str__ method. Running this code
prints
to the screen.

![$${ {< \_\_main\_\_.Rational object at 0x113bc70 > ] }}$$](A978-1-4471-6642-9_7_Chapter_TeX2GIF_IEq5.gif)

In Example 7.13 the __str__ was added and rational numbers
printed nicely, but Example 7.14 shows that the Python interpreter does
not use __str__ when
printing a list of rationals. When printing a list, Python is
producing a string representation of the list that would be
suitable for Python to evaluate later to rebuild the list. If
Python tried to read a number like
in the list, it would
not know what to do with it. However, there is another hook that
allows the programmer to determine the best representation of an
object for Python’s purposes.

Example
7.15
So, what is the difference between
converting to a string and converting to a Python representation? A
string version of an object can be in whatever format the
programmer determines is best. But, a Python representation should
be in a format so that if the built-in Python function eval is called on it, it will evaluate
to its original value. The eval function is given an expression
contained in a string and evaluates the expression to produce the
Python value contained in the string. The appropriate
representation for most programmer-defined classes is to use the
same form that is required to construct the object in the first
place. To construct the rational number
we had to write Rational(4,5). For the eval function to correctly evaluate a
string containing a Rational, the eval function should be given a
rational in the Rational(numerator,denominator) form, not the
form.


There is another Python hook that
controls how sorting is performed in Python. For any type of object
in Python, if there is a natural ordering to those objects, Python
can sort a list of them.
Example
7.16
Here is some code that sorts a list of
names, alphabetically. This code, when run, prints the list
[‘Freeman’, ‘Gorman’, ‘Lee’,
‘Lie’, ‘Morgan’] to the screen.

If we attempt to sort the list
lst from
Example 7.14, Python will complain with the following
error message: builtins.TypeError:
unorderable types: Rational
().
While we have an understanding of rational numbers, Python has no
way of understanding that the class of Rational numbers represents
an ordered collection of values. To tell Python that it is an
ordered collection, we have to implement the __lt__ method. To compare any two
rational numbers, we must first make sure they have a common
denominator. Once we have a common denominator, the numerator of
the two rational numbers must be converted to units for the common
denominator. It turns out we don’t really need the common
denominator at all. We just need the converted numerators. The
__lt__ method must return
True if the object self
references is less than the object that other references and it must return
False otherwise.

Example
7.17
The following __lt__ method, when added to the class
in Example 7.12 converts the two numerators to their
common denominator form so they can be compared.

7.6 Review Questions
- 1.
What is another name for a class in Python?
- 2.
What is the relationship between classes and objects?
- 3.
What is the purpose of the __init__ method in a class definition?
- 4.
Computer scientists say that objects have both state and behavior. What do state and behavior refer to in a class definition?
- 5.
How do you create an object in Python?
- 6.
In a class definition, when you see the word self, what does self refer to?
- 7.
What is a superclass? Explain what the term means and give an example.
- 8.
What is the benefit of inheritance in Python?
- 9.
What does it mean for polymorphism to exist in a program? Why would you want this?
- 10.
How do the __str__ and the __repr__ methods differ? Why are they both needed?
- 11.
To be able to sort an ordered collection of your favorite type of objects, what method must be implemented on the objects?
7.7 Exercises
- 1.
Go back to the original Reminder! program and redo it so that the Reminder! program contains a class called Reminder that replaces the parallel lists of reminders and notes with one list of reminders. This list should be a list of Reminder objects. A Reminder object keeps track of its x,y location on the screen. It also has some text that is provided when it is created. A Reminder must take care of creating the Text and Toplevel objects so a note can be displayed. Finally, the methods defined on a Reminder include undraw (to withdraw the window), getX to return the X value of the window location, getY similarly gets the Y value of the window location. The getText method should return the text field. Finally, the setDeleteHandler should set the handler to be called when a reminder is deleted. Write this class and modify the Reminder! application to use this new class.Here is an outline of the Reminder class definition. You need to finish defining it and alter the program to use it.
- 2.
Modify your address book program to use a class for address book cards. Call the new class AddressCard. An address card contains all the information for an address book entry including last and first name, street, city, state, zip, phone, and mobile phone number. To use the AddressCard class you need to modify the program so it stores all AddressCards in a list. The program should read all the addresses when it starts and make one AddressCard object for each address in the file. You will also write all the cards in the list to a file when the program terminates. Look at the code in Chap. 15 to see how this can be done.You will want to include three hook methods in your AddressCard class. The __str__ method should be included to convert an AddressCard to a string. To do this you will want to return a string representation of the object as discussed in the chapter. The AddressCard entry should convert to a string as follows:The second special method is the __lt__ method. This method compares two AddressCard objects as described for Rationals in the chapter. Your __lt__ method should return True if the last name, first name of self is less than the last name, first name of the other AddressCard.A third special method is the __eq__ method. This method compares two AddressCard objects and is used by the index method on lists. If self is equal to other then True should be returned. If self is not equal to other then False should be returned. Here is how you might write this function.
- 3.
In this exercise you are to implement a game of Blackjack using the turtle package. Blackjack is a simple game with simple rules. In this exercise you get practice using Object-Oriented Programming to implement a fairly complex program.Rules of the GameBlackjack is played by dealing two cards to each player and the dealer. The player’s cards are face up. The dealer’s first card is face down and the second is face up.The goal is to get to 21 points. Each face card is worth 10 points. The Ace is worth 1 or 11 points depending on which is better for your hand. All other cards are worth their face value.The player bets first. Then he/she asks for cards (hits) until they are satisfied with their score or they go over. If they have not gone over, the dealer then draws cards until the dealer hand is 17 or over. If the dealer goes over 21, the player wins. Otherwise, the player wins if his/her score is greater than the dealer’s score.If the player gets a blackjack (21 with only two cards) then the player gets paid at a 3:2 ratio. Otherwise it is a 1:1 ratio payback.Writing the GameYou should write this game incrementally. That means, write a little bit and test that little bit before going on. You don’t want to debug this whole program after writing all the code.You will need to implement a Card class. A Card object can inherit from RawTurtle. When you create a Card object you will want to give it an image for the front and back. The images can be downloaded from the text website. Download the cards.zip file, and then unzip it in the same folder where you will write your program. The cards folder should be a subfolder of the folder where you write your program.The card images are named 1.gif, 2.gif, and so on. The back image is labeled back.gif. Images 1, 2, 3, 4 are the Aces. Images 5, 6, 7, 8 are the Kings and so on. To get the correct rank for a card you can use the formula
where val is the value of the card name. If the formula determines the rank is 14 it should be changed to 11. Ranks from 10–13 should be changed to 10.
The Card class will have at least four methods. You may want to define more. Here is a suggestion for the methods you should write.-
isFaceDown—This method returns true if the card is face down. It returns false if the card is face up.
-
setFaceDown—This method sets the Turtle shape to be the back of the card and remembers that it is now face down.
-
setFaceUp—This method sets the Turtle shape to be the face of the card and remembers that the card is now face up.
-
getBlackJackRank—This method returns the Blackjack rank of the card.
The main part of the program is placing buttons on the screen and handling the different button presses. Figure 7.6 shows what the application might look like during the playing of a hand. Figure 7.7 shows what the application might display at the end of that hand. Message boxes can be used to display the outcome of a hand. -
- 4.
Complete the Asteroids game available on the text web site as shown in Fig. 7.8. The Asteroids video game was originally designed and written by Atari. It was released to the public in 1979. In the game the player controls a spaceship that navigates space and blows up asteroids by shooting at them.When an asteroid is hit, the player scores points and the asteroid splits into two smaller asteroids. The largest asteroids are worth 20 points. Each medium asteroid is worth 50 points. The smallest asteroids are worth 100 points each. When the spaceship hits a small asteroid it is obliterated into dust and it disappears completely from the game.If an asteroid collides with the spaceship, the spaceship is destroyed, the asteroid that collided with it is destroyed (resulting in no points) and the player gets a new spaceship. The game starts with four spaceships total (the original game started with only three).Code is available on the text’s web site. The downloadable code makes the ship turn left when 4 is pressed. The ship will also move forward when 5 is pressed. Complete the program by implementing the game as described above. Some lessons are available on the text’s web site that will guide you through many of the additions to the program described here. To make the game a little more interesting you should add one new level to this program. The second level should have 7 asteroids instead of 5 and you should get one more life if you have less than 4 when level 2 starts.
- 5.
In Chap. 4, XML documents were introduced. The example in that chapter was of drawing a picture contained in an XML file. To do this, several parallel lists were constructed to hold the data of the XML file. However, there were lots of None values placed in the lists because not all attributes applied to all graphics commands.A much better way of organizing the XML data would be to create a class for each different kind of graphics command. So a BeginFillCommand class would contain just the color attribute needed for the BeginFill graphics command. Likewise, the class associated with each different type of command would hold the attributes needed just for that command. Then, a draw method could be written for each class that draws or uses a turtle for the desired side-effiect. Each draw method should be passed a turtle. The BeginFillCommand’s draw method would use the turtle to set the fillcolor and then would invoke the begin_fill turtle method.Rewrite the XML drawing program from Chap. 4 by defining a class for each type of graphics command along with a draw method for each of them that given a turtle draws or otherwise has the desired side-effect. Have the program read the XML file and create one list of these graphics command objects. Then use a loop to iterate through these commands, drawing each of them to the screen. Once completed you will have eliminated all the parallel lists from the program and written it with a much more object-oriented approach.

Fig.
7.6
A Blackjack hand

Fig.
7.7
The end of a Blackjack hand

Fig.
7.8
Asteroids!
7.8 Solutions to Practice Problems
These are solutions to the practice
problems in this chapter. You should only consult these answers
after you have tried each of them for yourself first. Practice
problems are meant to help reinforce the material you have just
read so make use of them.
7.8.1 Solutions to Practice Problem 7.1
A numerator and denominator are
needed.

7.8.2 Solutions to Practice Problem 7.2

7.8.3 Solutions to Practice Problem 7.3

7.8.4 Solutions to Practice Problem 7.4
Download code and try it out. Here is
the Rectangle class in case you had trouble with defining it.

7.8.5 Solutions to Practice Problem 7.5
Create some GravityBall objects and
add them to the ballList. That’s all that needs to be done to have
gravity balls and regular balls bouncing around with each other.
The object on the left hand side of the dot in the ball
ball.move is where
polymorphism is at work. If ball is pointing to a Ball object, it
behaves as a Ball would. If ball is pointing to a GravityBall
object, then ball.move is
the GravityBall move method. It’s not the name on the left hand
side of the dot, its the object that the name refers to that
controls which methods are called.