When you’ve finished working through this sheet, you’ll have written a program that plays a surprisingly addictive game: a version of the classic console based game, robots, in which you’re surrounded by robots who are trying to catch you, and you have to outwit them by fooling them into crashing into one another.
This is quite a difficult sheet, especially since we are not going to give you quite as much help as you’ve had in previous sheets. You’re supposed to be learning to do things on your own, after all! However, this sheet does introduce a lot of things you haven’t seen before, so you should feel free to ask your teacher for help at any time.
We’d better begin by explaining exactly how the game works.
You’re being chased by robots. They are armed, and if a robot manages to catch you, you’re dead. You have no weapons. Fortunately, the robots are rather stupid. They always move towards you, even if there’s something in the way. If two robots collide then they both die, leaving a pile of junk. And if a robot collides with a pile of junk, it dies. So, what you’re trying to do is to position yourself so that when the robots try to chase you they run into each other!
It turns out that that’s a little too hard; it’s too easy to get into a position where all you can do is wait for the robots to catch you. So you’ll give the player the ability to teleport to a random place on the screen.
It’s simplest to make everything happen on a grid of squares. So the player can move in any of the 8 compass directions, and at each turn a robot will move one square in one of those 8 directions; for instance, if the robot is north and east of the player then it will move one square south and one square west.
Let’s begin by thinking about what needs to happen when you play the game.
There’s a lot of stuff here. Let’s start, as usual, by writing some easy bits.
All the action takes place on a grid. Your graphics window is 640 pixels by 480; let’s make the grid 64 by 48 squares, each 10 pixels on a side. That’s a pretty good size.
You need to represent the player by something you can draw using the graphics facilities described in Sheet G (Gasp). We suggest that a filled-in circle will do as well as anything else.
So, let’s write a simple program that lets you move the player around the screen. This involves a bunch of stuff that’s new, so we’ll lead you through it carefully.
To make this program easier to follow — remember that it will be getting bigger and bigger as you add bits to it, until it’s a program to play the complete game of Robots — you’ll divide it up using functions. (See Sheet 3 ( Pretty Pictures), and Sheet F (Functions).) So, begin by typing in the following program in a file named robots.py:
from gasp import * # As usual begin_graphics() # So that you can draw things finished = False place_player() while not finished: move_player() end_graphics() # Finished!
If you try to run this program now, Python will complain that place_player and move_player are not defined. Let’s make stub versions of these functions so that we can get the program to run without complaint:
def place_player(): print "Here I am!" def move_player(): print "I'm moving..." update_when('key_pressed')
The command update_when('key_pressed') makes the program to wait for the user to press a key before doing anything else.
As the program develops, we’ll add bits to the program skeleton we’ve just created — for instance, there’ll be a place_robots() function added quite soon. For the moment, your task is to define those functions so that the player can move around the screen.
Let’s look at place_player(), which decides where on the screen the player should begin. This at least is easy.
Let’s have two variables inside this function called player_x and player_y, saying where the player is. You could either make them contain the player’s coordinates in pixels, or the coordinates in grid squares (which will be 10 times smaller, because each grid square is 10 pixels on a side).
Either is perfectly workable. We prefer the latter. You should probably go along with our preference, because for the rest of this worksheet we’re going to assume that’s what you have done!
We better explain this business about grid coordinates a bit more carefully. The graphics window is made up of 640 x 480 pixels. We’re chopping them up into 64 x 48 squares.
So, the bottom-left pixel of square (17, 23) is pixel (170, 230) and its top-right pixel is pixel (179, 239).
Back to place_player(). It needs to set the variables player_x and player_y randomly. player_x can have any value from 0 to 63; player_y can have any value from 0 to 47. If you can’t remember how to do that, look back at Sheet 2 (Turning the Tables) where random_between() was introduced.
And then it needs to put the player on the screen by saying something like Circle((player_x, player_y), 5, filled=True), except that those obviously aren’t the right coordinates for the center of the circle (because player_x etc are measured in grid squares, and Circle() wants coordinates in pixels). What you actually need is for the center of the circle to be in the middle of the grid square. So Circle((10*player_x+5, 10*player_y+5), 5, filled=True) should do the trick. (note: if you’re confused by the filled=True bit, you might like to take a look at Sheet F (Functions)), which describes keyword arguments.)
Now, you need to move that circle around in response to what the player does at the keyboard. This involves two new ideas – moving graphics, and keyboard handling. Let’s deal with the first one first.
In the Python Shell window, type the following:
>>> from gasp import * >>> begin_graphics() >>> c = Circle((320, 200), 5)
The last line still draws the circle, as you’ll have seen, but it does something else too: it returns a value, and that value can be used later to move the circle around (or remove it from the window completely).
So, try doing this:
>>> move_to(c, (300, 220))
The circle should move when you do that.
Write a small program that creates a ball (Circle) and has a loop that makes the ball move smoothly from the lower left corner of the screen (0, 0) to the upper right corner (640, 480). A few hints may be helpful:
One other thing:
You can probably guess what that does, but you should try it anyway.
That’s all very well, but of course no one will play this game if they don’t get to choose where the player moves! The easiest way to do this is to let the player use the keyboard. You’ll allow movement in 8 different directions...
... and of course you should allow the player to stay still. So you’ll need a 3 x 3 grid of keys. Your keyboard almost certainly has a numeric keypad on the right: the numbers 1-9 will do fine. So, for instance, pressing 7 should make the player move upwards and to the left.
Therefore, what you have to do inside move_player() is to test which of those keys — if any — is pressed.
The function update_when('key_pressed') returns a string with the keys that was pressed. Keys are represented by the characters they produce. Letter keys are represented by lowercase letters.
Run the following program, go over to the Graphics Window and press some keys. When you’re done, press the q key.
from gasp import * begin_graphics() key_text = Text("a", (320, 240), size=48) while True: key = update_when('key_pressed') remove_from_screen(key_text) key_text = Text(key, (320, 240), size=48) if key == 'q': # See Sheet C if you don't understand this break # See Sheet L if you aren't sure what this means end_graphics()
Which command is printing text onto the graphics window? Try using this command to display longer strings of text.
So, now you know how to tell what keys are pressed, and you know how to move an object around. So, now it’s time to put the two together...
Change place_player so that it puts the value returned from Circle() in a variable (call it player_shape); and ...write a move_player() function that uses keys_pressed() to see what keys are pressed, and moves the player if any of the keys 1 – 9 are pressed. Moving the player requires:
Eeek! we bet you find it doesn’t work. Specifically, the move_player() function will say it’s never heard of the variables you set in place_player(). What’s going on?
If you haven’t already read Sheet F (Functions), now might be a good time to glance at it.
The important point is that any variables you set in a function (e.g., player_x in place_player()) are local to that function: in other words, they only exist inside the function, and when the function returns they lose their values.
Usually this is a Good Thing — for reasons discussed briefly in Sheet F (Functions) — but here it’s a nuisance. Fortunately, there’s a cure.
Suppose you have a function definition that looks like this:
def f(): # blah blah blah x = 1 # blah blah blah
Then x is a local variable here, and calling f won’t make a variable called x that exists outside f:
>>> f() >>> print x Blah blah blah ERROR ERROR blah blah NameError: x
But if you add to the definition of f a line saying global x like this:
def f(): global x x = 1
(just after the def, and indented by the same amount as the rest of the definition), then the variable x inside f will be global — in other words, x will mean just the same inside f as it does outside. So the print x that gave an error with the other version of f will now happily print 1 .
We hope it’s clear that this bit of magic is what you need to fix the problem with place_player() and move_player(). Add global statments to both definitions.
At this point, you should have a little program that puts a circle on the screen and lets you move it around using the keyboard. Fair enough, but
Let’s deal with the second of those problems first. After the player’s move, see whether he’s off the edge — either coordinate negative, or x > 63, or y > 47. If so, repair the offending coordinate in what we hope is the obvious way. An even better approach is to check whether you are about to go out of bounds and if you are, don’t do it.
After making the variables global, change place_player and add move_player to your robots.py program so that you can move the player around the screen by pressing the number keys.
Here are some bits of the move_player function to help you:
def move_player(): global player_x, player_y, player_shape key = update_when('key_pressed') if key == '6' and player_x < 63: player_x += 1 elif key == '3': if player_x < 63: player_x += 1 if player_y > 0: player_y -= 1 # You fill in the rest here... move_to(player_shape, (10*player_x+5, 10*player_y+5))
We’ve introduced a few things you haven’t seen before in the above challenge:
Eventually, you’ll have the player being pursued by a horde of robots. First, though, a simpler version of the program in which there’s only one robot.
Before the line of your program that says place_player(), add another that says place_robot(). Write the place_robot() function: it should be very much like place_player(), except of course that you should (1) use different names for the variables and (2) draw a different symbol. We suggest a box, unfilled. You may need to think a bit about exactly where to put the corners of the box.
Remember to use the global statement as you did in place_player().
After the move_player() line, add another that says move_robot(). Now you need to work out how to move the robot. The robot should move according to the following rules:
So, if a robot is both left of the player and above the player, it will move down and to the right. This diagram may make it clearer how the robots move.
This function doesn’t need to check whether the robot is trying to walk off the edge of the screen. Can you see why?
Try your program. Even if you haven’t made any mistakes, it still won’t be much fun to play, for the following reason...
This problem is easy to fix. After the call move_robot(), add another function call: check_collisions(). Then write a function check_collisions(), which tests whether the player has been caught by the robot. That happens if, after the robot’s move, the player and the robot are in the same place. And that happens if player_x and robot_x are equal, and player_y and robot_y are equal. You probably need to look at Sheet C (Conditions and Conditionals) to find out how to say if this is true and that is true , if you haven’t already done that.
If they are in the same place, the program should print a message saying something like “You’ve been caught!”, and set that finished variable that gets tested at the top of the main while loop to something other than False (True would be an excellent choice).
Then the program will finish when the player gets caught. You can even use the Text object you saw a bit earlier to display this message in the graphics window. GASP also has a function sleep in it that tells the computer to do nothing for a desired amount of time. sleep(3) will cause the program to do nothing for 3 seconds.
Once you’ve fixed that problem and tried your program, you’ll probably notice one or two more.
It will be easier to fix the first problem after we have fixed the second one.
The trick is to change place_player so that it never puts the player in the same place as the robot. How to do that? Just place the player at random; if he’s in the same place as the robot, try again (still at random) and check again (and again, and again, if necessary, until the player and robot are in different places). This is just a while loop again. Because the test in a while loop always has to go at the start, it will have to look (in outline) something like this:
choose the player's position at random while the player and robot haven't collided: choose the player's position at random
Notice that you have to choose the player’s position at random twice here. This is a good indication that you should put it in a function – whenever you have something that gets done more than once in your program, you should think about making it into a function.
In fact, choose the player’s position at random is already in a function. The function is called place_player, and that’s exactly what it does. So we need a new function to do the more complicated thing above; let’s call it safely_place_player, and have it use place_player to place the player:
def safely_place_player(): place_player() while collided(): place_player()
Notice that we are introducing another new function here, collided, whose job it will be to check whether the player and the robot are in the same place (you already know how to do that, right?), and to return True or False depending on the result.
You can use collided here and also in check_collisions. If you don’t already know about returning a value from a function , have a look at Sheet F (Functions) now. Also, if you still haven’t read Sheet C (Conditions and Conditionals), now would be a very good time.
The problem is that you’ve just introduced a bug into your program that may not get noticed for awhile, and when you see it later, it will be hard to figure out why it is happening. place_player as we’ve written it is only meant to be called once. It makes a circle and gives it the name player_shape. We use this name to move the circle around the graphics window.
If you call place_player again, player_shape will be the name of a new circle, and the old circle won’t have a name anymore. So it will sit there in your graphics window and you won’t be able to move it or remove it from the screen.
The reason that you might not notice this bug for a long while if we didn’t just tell you about it is that it will be pretty rare at this stage for the player to be randomly placed on top of the robot, so safely_place_player will usually call place_player only once, and you won’t notice the bug.
Later, when there are lots of robots and the problem becomes much more likely, you will see these circles on the graphics window and not know where they came from.
The easiest way to fix this problem is:
Now that you have fixed the second problem, it won’t be hard to fix the first one. You’ll let the player teleport — move instantaneously to a new place on the screen.
You don’t want them ever to land on top of a robot. So, in move_player, test for the 5 key being pressed; if it’s pressed, move the player to a random empty space on the screen... which you already know how to do — just call safely_place_player().
There is a problem with just adding a new elif test to move_player and letting that call safely_place_player. It is again the kind of bug you may not notice for awhile (those are the peskiest kind of bugs!).
safely_place_player makes sure not to place the player on top of the robot, but very occasionally it will place it immediately next to the robot. It will then be the robot’s turn to move, and... “You’ve been caught!” will appear on the screen. This is not the kind of safe teleport we had in mind.
A good solution to this problem is to check for the teleport at the beginning of move_player — immmediately after the key = update_when('key_pressed') command, and then to let the player have a chance to move again before the robot’s move. You could start by adding something like this:
if key == '5': remove_from_screen(player_shape) safely_place_player() key = update_when('key_pressed')
This almost does what we want, but there is still a problem. What will happen if you teleport twice in a row?
Let’s take a moment to review what you have so far. The player and one robot are placed on the screen, at random. They both move around, in the correct sort of way. If they collide, the game ends. The player can teleport.
This is pretty good. There are just two more really important things to add.
The first of these is a pretty major change. If you haven’t already been saving lots of different versions of your program, now would be a very good time to make a copy of the program as it is now. You’re about to perform major surgery on it, and it would be wise to keep a copy of how it was before you started operating.
Before you do that, though, some minor surgery that will make the major surgery easier. To explain the minor surgery, a major digression will be needed, so here is one.
Try doing this in your Python Shell window.
>>> class Robot: ... pass ... >>> fred = Robot() >>> fred.x = 100 >>> fred.y = 200 >>> print fred.x, fred.y
We’re sure you can guess what that last ``print`` statement will print.
What you’ve done is to define a class called Robot. Roughly, class means kind of object . In other words, you’ve told the computer In the future, I might want to talk about a new kind of thing. Those things are called Robots. You can do all kinds of clever things with classes, but you won’t need anything fancy in this sheet; just the very simplest things.
All pass means is we have nothing to say here . It’s sometimes used in if and while statements; so, for instance, to sit and wait until a key is pressed in the graphics window you could say
while not keys_pressed(): pass
which translates as repeatedly, as long as there are no keys pressed, do nothing . In this class definition, it means There’s nothing else to say about the Robot class. .
What does the line fred = Robot() mean? Remember we told you about a new kind of thing called a Robot? Well, we want one of those. Call it fred. The thing that gets named fred is what’s called an instance of the Robot class.
Class instances (like fred in the little example above) can have things called attributes. For instance, fred.x is an attribute of fred. Attributes are rather like variables; you can do all the same things with them that you can with variables. But an attribute is really more like an array element, or — if you’ve read Sheet D (Dictionaries and Tuples) like a value in a dictionary: it’s part of an object.
For instance, after the example above, suppose you say
>>> bill = fred >>> print bill.x
(assuming this is a continuation of the previous interpreter session...)
Then the machine will print 100, just as it would have if we’d asked for fred.x, because fred and bill are just different names for the same object, whose x attribute is 100.
What on earth does all this have to do with your game? Well, there are three separate pieces of information associated with the player and with the robot in the game: two coordinates, player_x and player_y, and one other thing, player_shape, used for moving the shape on the screen that represents the player.
Incidentally, the thing called player_shape is actually a class instance, though its class definition is slightly more complicated than that of Robot in the example above. You’re about to have, not just one robot, but lots of them. Your program will be much neater if all the information about each robot is collected together into a single object.
In fact, this is an important idea to know whenever you’re designing a program:
Whenever you have several different pieces of information that describe a single object, try to avoid using several different variables for them. Put them together in a class instance, or a list, or a tuple, or a dictionary, or something.
Improve your program by grouping sets of variables together into class instances:
At the beginning of the program (after from gasp...), add two class definitions:
class Player: pass class Robot: pass
At the beginning of place_player (after the global statement), say player = Player().
At the beginning of place_robot, say robot = Robot().
Change the global statements so that they only globalise the variables player (instead of player_x etc) or robot (instead of robot_x etc).
Change all references to player_x, player_y and player_shape to player.x, player.y and player.shape.
Do the same for robot.
Test your program to be sure it still works. If it doesn’t, fix any errors until it does.
Now would be another good time to save a copy of your program!
You’ve already met lists, very briefly, in Sheet 1 (Introducing Python). It would be a good idea, at this point, to have a quick look at Sheet A (Lists); you don’t need to absorb everything on it, but reminding yourself of some things lists can do would be a good move.
What you’ll do is to have, instead of a single variable robot, a list robots containing all the robots on the screen. Each element of the list will be an instance of the Robot class.
So, what needs to change?
place_robot should be renamed place_robots in both the definition and the call.
rename robot to robots in the global statement at the beginning of the function.
Make a new variable named numbots in the main body of the program that will determine the number of robots that place_robots will create.
place_robots should make numbots new Robot instances and put them together in a list.
hint: Use a for loop like this:
for i in range(numbots): # all the stuff you need to do to make a robot here... robots.append(robot)
You will need to create robots as an empty list before the for loop.
To be able to test this without crashing the program, comment out the calls to each of the functions we have temporarily broken until we can fix each of them in turn. All you want now is a call to place_robots, so your main program should look something like this:
begin_graphics() numbots = 10 finished = False place_robots() #safely_place_player() #while not finished: #move_player() #move_robot() #check_collisions() update_when('key_pressed') end_graphics()
Make all these changes and test your program. You should see a graphics window with 10 robots, which closes as soon as you press any key.
Well, you probably saw 10 robots, but you haven’t checked to see if any of the robots ended up being randomly placed on top of another one. We already have a function, collided which checks whether the player and a single robot are in the same place. That won’t be very useful anymore, since we will be interested in whether or not the player has hit any robot.
Let’s change collided so that it does this, and at the same time can be used to see whether a new robot has hit any of those already in the list.
To do this we will make the player (or robot) and the list of robots arguments which we pass into the function (now would be a good time to read over Sheet F (Functions) with special attention to the section on functions with arguments):
def collided(thing1, list_of_things): for thing2 in list_of_things: if thing1.x == thing2.x and thing1.y == thing2.y: return True return False
Look at this function carefully until you understand why it works. collided should return true as soon as it finds something in the list in the same place as the thing you are checking. If it never finds anything, it finishes the for loop and hits the return False statement.
Since both robots and the player have x and y attributes, we can use this same function with either one.
With a few modifications to place_robots, we can use our new collided function to keep robots from being placed on top of each other. We will make use of the built-in len function that tells how many items are in a list:
def place_robots(): global robots robots =  while len(robots) < numbots: robot = Robot() robot.x = random_between(0, 63) robot.y = random_between(0, 47) if not collided(robot, robots): robot.shape = Box((10*robot.x, 10*robot.y), 10, 10) robots.append(robot)
Let’s stop a minute to talk about how this works. Since it is a matter of chance whether a robot will end up placed on top of another one, we don’t know in advance how many times that will happen, so we can’t use a for loop.
What we do instead is use a while loop, and keep trying to add new robots to the list, discarding those that land on top of previous ones, until we have all the robots in the list that we want (when len(robots) == numbots).
We delay adding a shape attribute to each candidate robot until we know it hasn’t landed on any other robots, so we don’t litter our graphics screen with boxes.
Now let’s make the robots move and check for collisions with the player. We leave the details of making this work up to you.
OK, we everything working again that we did before we decided to add lots of robots, but we still don’t have a way to win the game, since our robots are still invincible. We can move around and teleport until they all end up on top of each other, but the darn things won’t die.
To get them to die will be the trickiest part of the program, because it involves checking whether or not each of the robots has collided with any of the others, and then:
Before solving these problems, we need to decide how we are going to represent the pieces of junk. Pieces of junk and live robots should differ in two ways:
Let’s create a new empty list, called junk, where we will place robots that have died. Whenever we find two robots that have collided, we will change one of them into a piece of junk and add it to the junk list.
Now let’s figure out how we can handle collisions...
We need to be able to check whether two robots have collided. It turns out that we will want to know more than just “have some robots collided?”; we need to know which robots, so that we can remove one of them and turn the other into junk.
The best thing to do is to have a function that determines, for a particular robot, whether any robot earlier in the list has collided with it. Then, if we run through the whole list checking this, we’ll pick up every collision exactly once. Can you see why? The function will return either False or the Robot instance that has crashed with the robot we’re asking about. Since we are sending it one of the robots that crashes, and the other one is returned, we get both the robots we are looking for:
def robot_crashed(the_bot): for a_bot in robots: if a_bot == the_bot: # we have reached our self in the list return False if a_bot.x == the_bot.x and a_bot.y == the_bot.y: # a crash return a_bot return False
By looping through the robot list again, and sending each robot to robot_crashed in turn, we can identify all robots that have crashed into another robot. The question is, what do we do with them once we find them?
When a collision happens, we need to remove one of the colliding robots from circulation completely. If you’ve read Sheet L (Loops), you’ll know about the del statement, which can remove an item from a list. You might be tempted to try to use del to remove one of the robots, but this approach can produce really weird errors, since you would be modifying a list while you are looping through it.
To understand why this is a problem, a detour is in order...
Deleting things from a list while looping over the list is dangerous. Here are a couple of terrible examples of the sort of thing that can happen:
>>> my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for i in range(0,len(my_list)): ... if my_list[i] == 3 or my_list[i] == 7: ... del my_list[i] ... Traceback (innermost last): File "<stdin>", line 2, in <module> IndexError: list index out of range >>> my_list [0, 1, 2, 4, 5, 6, 8, 9]
OK, let’s try another way.
>>> my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for item in my_list: ... if item == 3 or item == 7: ... del my_list[my_list.index(item)] ... >>> my_list [0, 1, 2, 4, 5, 6, 8, 9]
Looks like it works. Let’s try another example.
>>> my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for item in my_list: ... if item == 3 or item == 4: ... del my_list[my_list.index(item)] ... >>> my_list [0, 1, 2, 4, 5, 6, 7, 8, 9]
Uh-oh. 4’s still there.
Once you’ve done that, it might occur to you to try to repair the first example like this:
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for i in range(0, len(my_list)): if my_list[i] == 3 or my_list[i] == 7: del my_list[i] i = i - 1
Unfortunately, this behaves in exactly the same way as the other version did.
If you’ve managed all those, you’ll probably (1) understand lists and loops pretty well, and (2) be very frustrated. There are a couple of tricks that will work. For instance, if you repeat your second attempt, but loop backwards, that will work.
An even simpler way is to build a completely new list to replace the old one; and that’s what we will do here. So...
Everything we have left to do can be handled by the check_collisions function, so let’s get to work on that. To begin with, it should look something like this:
def check_collisions(): global finished, robots, junk # Handle player crashes into robot if collided(player, robots+junk): finished = True Text("You've been caught!", (120, 240), size=36) sleep(3) return
The return statement (and the global junk) has just been added now. It wasn’t needed before since sleep(3) was the end of the function, but now we will be adding to it.
Add the function robot_crashed to your program, as defined above. Make sure your check_collisions function looks like the one above. Create an empty list in the main body of your program named junk and make junk a global variable in check_collisions. Then inside check_collisions:
Create an empty list named surviving_robots.
Loop through the robots list, doing the following on with each robot:
if collided(robot, junk): continue
immediately after the start of the for loop. This will check if the robot has hit a piece of junk, and disgard it (by not adding it to surviving_robots). continue tells python to skip the rest of the body of the loop and start immediately with the next item in the list.
Call robot_crashed on each robot that makes it past the junk test, assigning the result to a new variable called jbot.
If jbot is False, append the robot to surviving_robots.
Otherwise (else), jbot is a robot that has crashed, so change it into junk and append it to the junk list:
remove_from_screen(jbot.shape) jbot.shape = Box((10*jbot.x, 10*jbot.y), 10, 10, filled=True) junk.append(jbot)
After the loop finishes, reassign robots to an empty list.
Loop through surviving_robots, checking for collisions with junk (using collided) and appending any robots that are not in junk back to robots.
Finally, if robots is empty (if not robots):
At this point you should pretty much have a working game, though it’ll probably take a little while to get the bugs out of it. Congratulations! This has been a long sheet, with lots of new ideas in it; well done for surviving to the end.
The game works, but there are plenty of things it would be nice to add.
You’ve now reached the end of this sheet. Congratulations! Some things you might not have looked at yet, and might find interesting:
When you’ve done that, you could go on to Sheet 6: Chomp, in which you’ll write another classic computer game using an object oriented approach.
Warning: Writing computer programs is an addictive activity.