This chapter begins our study of the Robot Programming Language. We will start with a detailed explanation of the primitive instructions that are built into every robot's vocabulary. Using these instructions, we can instruct any robot to move through the world and handle beepers. Section 2.6 shows a complete robot program and discusses the elementary punctuation and grammar rules of the robot programming language. By the end of this chapter we will be able to write programs that instruct robots to perform simple obstacle avoidance and beeper transportation tasks.
Before explaining the primitive instructions of the robot programming language, we must first define the technical term execute: A robot executes an instruction by performing the instruction's associated action or actions. The robot executes a program by executing a sequence of instructions (script) that are given to it by the helicopter pilot. Each instruction in such a sequence is delivered to the robot in a message, which directs one robot to perform one instruction in the program.
Every robot understands two primitive instructions that change its position. The first of these instructions is move , which changes a robot's location.
move
When a robot is sent a move message it executes a move instruction and moves forward one block; it continues to face the same direction. To avoid damage, a robot will not move forward if it sees a wall section or boundary wall between its current location and the corner to which it would move. Instead, it turns itself off. This action, called an error shutoff, will be explained further in Section 2.7.
From this definition we see that a robot executes a move instruction by moving forward to the next corner. However, the robot performs an error shutoff when its front is blocked.
Figure 2-1 A: A Robot in the Initial Figure 2-1 B: A Robot in the Final
Situation before Situation after Executing
a move Instruction a move Instruction
Figure 2-1 shows the successful execution of a move instruction. The wall section is more than one half-block away and cannot block this robot's move.
In contrast, Figure 2-2 shows an incorrect attempt to move. When this robot tries to execute a move instruction in this situation, it sees a wall section. Relying on its self-preservation instinct, it performs an error shutoff.
Figure 2-2 The Result of a robot Attempting to move When Its Front Is Blocked Is an Error Shutoff.
The second primitive instruction that changes a robot's position is turnLeft . This instruction changes the direction in which the robot is facing but does not alter its location.
turnLeft
When a robot is sent a turnLeft message it executes a turnLeft instruction by pivoting 90 degrees to the left. The robot remains on the same street corner while executing a turnLeft instruction. Because it is impossible for a wall section to block a robot's turn, turnLeft cannot cause an error shutoff.
A robot always starts a task on some corner, facing either north, south, east, or west. A robot cannot travel fractions of a block or turn at other than 90 degree angles. Although move and turnLeft change the robot's position, after executing either of these instructions, the robot still is on some corner and still is facing one of the four compass directions.
Karel-Werke's designer purposely did not provide a built-in turnRight instruction. Would adding a turnRight to the primitive instructions allow the robot to perform any task it cannot accomplish without one? A moment's thought-and the right flash of insight-shows that the turnRight instruction is unnecessary; it does not permit robots to accomplish any new tasks. The key observation for verifying this conclusion is that a robot can manage the equivalent of a turnRight instruction by executing three turnLeft instructions.
We need a way to tell a robot that its task is finished. The turnOff instruction fulfills this requirement.
turnOff
When a robot is sent a turnOff message, it executes a turnOff instruction. It turns off and is incapable of executing any more instructions until restarted on another task. The last instruction executed by every robot in a program is usually a turnOff instruction. This is not strictly necessary, however. The robot will generate an error (exception, in techno-speak) for any messages it receives after it executes turnOff.
Every robot understands two instructions that permit it to handle beepers. These two instructions perform opposite actions.
pickBeeper
When a robot is sent a pickBeeper message, it executes a pickBeeper instruction. It picks up a beeper from the corner on which it is standing and then deposits the beeper in its beeper-bag. If a pickBeeper instruction is attempted on a beeperless corner, the robot performs an error shutoff. On a corner with more than one beeper the robot picks up one, and only one, of the beepers and then places it in the beeper-bag.
putBeeper
When a robot is sent a putBeeper message, it executes a putBeeper instruction by extracting a beeper from its beeper-bag and placing the beeper on the current street corner. If a robot tries to execute a putBeeper instruction with an empty beeper-bag, the robot performs an error shutoff. If the robot has more than one beeper in its beeper-bag, it extracts one, and only one, beeper and places it on the current corner.
Beepers are so small that robots can move right by them; only wall sections and boundary walls can block a robot's movement. Robots are also very adept at avoiding each other if two or more show up on the same corner simultaneously.
All robots produced by Karel-Werke have at least the capabilities just described. As we will see, such robots are very primitive, and we might like robots with additional abilities. Therefore, we must have some way to describe those extra abilities so that the factory can build a robot to our specifications. Karel-Werke employs a simple robot programming language to describe both robot abilities and the lists of robot instructions, called programs. The formal name for the description of a robot instruction is method. The factory begins each robot creation by first building a RobotSkeleton that has no actual capabilities, but has interfaces for the above methods. The simple model of robot described above is called the UrRobot class[1] and it is built by actually implementing the methods. A class is a description of robots of the same kind. A class is like a production line in the factory that makes robots. The specification, or interface, of the RobotSkeleton class in the robot programming language follows.
class _RobotSkeleton:
""" Defines the basic structure of a simple robot produced by the
Karel Werke. This skeleton has no working parts. If you try to send a
message to such a machine, it will simply signal an error.
"""
def move(self):
"Move one block forward (standard version)"
raise NotImplementedError("move not yet implemented.")
def turnLeft(self):
"Turn 90 degrees to the left (standard version)"
raise NotImplementedError("turnLeft not yet implemented.")
def pickBeeper(self):
ÒÓÓPick one beeper from the current corner if present (standard
version)ÓÓÓ
raise NotImplementedError("pickBeeper not yet implemented.")
def putBeeper(self):
ÒÓÓPut one beeper on the current corner if holding any (standard
version)ÓÓÓ
raise NotImplementedError( "putBeeper not yet implemented.")
def turnOff(self):
"Turn off and accept no further instructions (standard version)"
raise NotImplementedError("turnOff not yet implemented.")
Following the model class name is a string comment and then a list of instructions (methods) for this kind of robot. The list is always written indented four spaces for each level. The defs themselves are one level and the instructions defining each def are the next level. The quoted statements are just comments that explain the purpose of the class and each method. A quoted string should have matching quotes. If you need a string to flow onto additional lines, it should begin and end with three quotes. The raise statements are how a robot signals an error has occurred. In general, quoted strings can use single quotes (apostrophes) as well, but they must be matched.
These defs are the descriptions of how a RobotSkeletion would carry out each of these instructions. Namely, it would just signal that it could not do anything since the instruction isnÕt implemented here. It is in UrRobot that we see the first actual implementation of the methods. In fact, the robot factory wonÕt actually release one of these skeleton. Their only purpose is in preproduction for an UrRobot. An UrRobot has all of these methods and a few more that we shall see along the way, but the factory has completed the construction and is willing to put them into the world. Think of a RobotSkeleton as if it is a partially completed robot as it rolls off the first segment of the production line at the Karel-Werke.
While these instructions donÕt really do anything, they have the correct form for the Python language. The word class starts in column one of the file in which it appears (robota.py). Each method def is indented four spaces, and the body of each of the definitions is indented an additional four spaces. This indenting is very important in the Robot Programming Language as the language processor depends on it to understand our instructions for the robots. Likewise, the colons that appear on the ends of the class and def lines are essential. And, in case you noticed and are wondering, the actually spelling of the class is _RobotSkeleton. This is just a way of making these objects less visible to the world. After all, they are intended only for internal use in the factory.
The class UrRobot is built from the skeleton class. We sometimes say that the skeleton here defines the interface of the UrRobot class and that UrRobot is a sub-class of _RobotSkeleton. UrRobot just makes these incipient capabilities real. In the Robot Programming Language, we say that UrRobot inherits the capabilities of the skeleton class, but we shall wait a bit before we show the details of inheritance. So while a skeleton robot might ÒlookÓ like a real robot, itÕs ÒlegsÓ wonÕt move, nor itÕs arm, etc. But the UrRobot is fully functional and ready to do your bidding. The mechanism to derive UrRobot from _RobotSkeleton is the class definition, which discuss in detail in the next chapter, but in this case, it has a form like:
class UrRobot(_RobotSkeleton, . . .) :
. . . # implementations of the inherited methods
The five methods, move through turnOff, name actions that UrRobots can perform. We defined each of these actions in the foregoing sections, and we will see many examples of their use throughout this book. These methods are all executed for their effect (they do something), but return no feedback to the robot program when executed. Later we will see additional methods that do produce feedback when executed, rather than changing the state of the robot. Said differently, the instructions here something as opposed to telling us something that the robot remembers: robots do things and they remember things. The matching parentheses surrounding the word self are always required in a def of a new instruction that a robot can carry out. The self in question here is the robot itself. Since we can have many robots we need to be able to distinguish them, and each robot knows itself.
Note that a class is not a robot. It is just a description (blueprint, specification) of robots of the same kind. The class of a robot tells us its capabilities (methods). If we know the class of a robot we know what the robot can do and what it can remember. We haven't created any robots yet, but are about to do so.
A sample task for an UrRobot might be to start at the origin, facing east, and then walk three blocks east to a corner known to have a beeper, pick up the beeper, and turnOff on that corner. A complete program to accomplish this task is shown next. In this program we name the robot karel , but we could use any convenient name. Note that we don't capitalize the names of robots. They aren't people, after all. In Python, the name used to refer to an object (including a robot) is called a "reference variable" and the convention is not to capitalize these in our Python programs. The names of classes like UrRobot, on the other hand, are usually capitalized.
from karel.robota import UrRobot
from karel.robota import East
if __name__ == Ô__main__Õ :
karel = UrRobot(1, 1,
East, 0)
# Deliver the robot to the origin (1,1),
# facing east, with no beepers.
karel.move()
karel.move()
karel.move()
karel.pickBeeper()
karel.turnOff()
Complete programs will be discussed in the next section.
In this section we describe a task for a robot named karel and a complete program that instructs it to perform the task. The task, illustrated in Figure 2-3, is to transport the beeper from 2nd Street and 4th Avenue to 4th Street and 5th Avenue. After karel has put down the beeper, it must move one block farther north before turning off.
The following program instructs karel to perform this task. The program uses all of the methods available to robots in the UrRobot class, a few new words from the robot programming vocabulary, and punctuation symbols such as the period and colon. We will first discuss karel's execution of this program, and then analyze the general structure of all robot programs.
Initial situation Final situation
Figure 2-3 The Initial and Final Situations of KarelÕs task
from karel.robota import UrRobot
from karel.robota import East
if __name__ == '__main__' :
karel = UrRobot(2, 2, East, 0)
karel.move()
karel.move()
karel.pickBeeper()
karel.move()
karel.turnLeft()
karel.move()
karel.move()
karel.putBeeper()
karel.move()
karel.turnOff()
See Section 1 and 2 of the Appendix for more on the details of the above including the import statement.
We must note that this is not the only sequence of messages that will correctly perform the stated task. Although it is obvious and direct, this is just one of many sequences that will accomplish the task.
The first two lines here make the names UrRobot and East available here, as they are both defined in the module karel.robota. The third line introduces the main task block and it is the same in every program. The fourth line creates a robot we will refer to as karel, and the remaining indented lines following that are the task for karel. Indentation level is very significant in the Robot Programming Language.
A set of messages to one or more robots is called a task. A task, if correctly written, can be executed by the Python system. The first instruction in the main task block constructs the robot, associates the name karel with it, and delivers it, ready to run, from the factory to 2nd Street and 2nd Avenue, facing east with no beepers in its beeper-bag. This instruction is not, technically speaking, a message since it is not addressed to any robot. This statement can be thought of as a delivery specification. It instructs the helicopter pilot how to set up the robot when it is delivered. The delivery specification also names the specific type or class of robot that we want delivered. Here we want an UrRobot .
The remaining lines of the main task block instruct karel how to carry out the task. These messages are sent to karel by the helicopter pilot, as described next.
Before a program can be executed in a world, the program is read at the factory to make sure it has no errors. We will discuss errors later; for now, we will assume that our program is correct. But the check at the factory is very cursory. It will check for colons in the right place, for example, but not for names misspelled.
How is a program executed? A program execution is begun after the helicopter pilot delivers the robot to the required corner and sets it up according to the delivery specification. Here we require that the UrRobot karel be set up on 2nd Street and 2nd Avenue, facing East, and with zero beepers in its beeper-bag. Then, for each additional command in the main task block, the pilot sends a corresponding electronic message to the robot named in that command. The message gives the instruction that the named robot is supposed to perform. These messages are relayed by the pilot to the robot through a special robot control satellite that hovers over the world. Since a robot can execute only one instruction at a time and since the satellite has a very limited communication capacity, only one message can be sent at a time. The pilot must wait for instruction completion before sending the next message. When the robot completes the current instruction, it sends a reply back to the pilot through the satellite indicating that the next message can be sent. Messages from the main task block are sent sequentially without omitting any messages in a strict top-to-bottom order. The pilot continues sending messages until either all messages in the main task block have been sent or the pilot attempts to send a message to a robot that has executed a turnOff or has performed an error shutoff.
It is also possible for robots to send messages to each other. When this occurs, the robot sending the message waits for the reply before continuing. This is to guarantee that the satellite communication channel is never overloaded. There is a subtle point here, however. The helicopter pilot only reads out the messages in the main task block. These messages contain the names of the robot's methods. The robot itself knows how to carry out the details of that method. We shall see how important this distinction is in the next chapter. A robot will only react to message sent specifically to it. This is important to remember when we have several robots.
To determine what a program does, we simulate, or trace, its execution. Simulating or tracing a robot program means that we must systematically execute the program exactly as the pilot and robots would, recording every action that takes place. We can simulate a robot program by using markers on a sheet of paper (representing robots and the world) or walking around on a rectangular grid. We simulate a robot program by following the sequence of messages in the order the pilot reads them to the robot. We will discuss tracing later, but in order to become proficient robot programmers, we must understand exactly how the pilot reads the program and the robot executes it. The ability to simulate a robot's behavior quickly and accurately is an important skill that we must acquire.
Let's follow a simulation of our program. In the following simulation (2, 4) means 2nd Street and 4th Avenue. In the following annotation we explain exactly what state the robot is left in after the execution of the instruction. Note that the symbol # (the hash symbol) is used in the simulation to introduce comments into our robot programs. Each comment begins with the # mark and continues to the end of the line. These comments are ignored by the pilot and by the robots; they are included only to aid our own understanding of the program. Here we use them to explain in detail each instruction as it will be executed. We note, however, that if the program is changed in any way, the comments are likely to become invalid.
if __name__ == '__main__' :
karel = UrRobot(2, 2, East, 0)
# A new robot named karel is
# constructed and delivered to
# (2,2), facing east. karel has
# no beepers in its beeper-bag.
karel.move() # karel moves east
# to (2, 3)
karel.move() # karel moves east
# to (2, 4)
karel.pickBeeper() # karel picks 1 beeper
# 1 beeper in bag
karel.move() # karel moves east
# to (2, 5)
karel.turnLeft() # karel remains on
# (2, 5), faces north
karel.move() # karel moves north
# to (3, 5)
karel.move() # karel moves north
# to (4, 5)
karel.putBeeper() # karel puts 1 beeper
# down, now 0 beepers
# in bag
karel.move() # karel moves north
# to (5, 5)
karel.turnOff() # karel remains on
# (5, 5) facing north
# and shuts off
Karel is done and we have verified that our program is correct through simulation by tracing the execution of the program.
Now that we have seen how a robot executes a program, let's explore the grammar rules of the robot programming language. The factory and pilots pay strict attention to grammar and punctuation rules, so our time is well spent carefully studying these rules. We start by dividing the symbols in a robot program into three groups. The first group consists of special symbols. It has members such as the punctuation marks like the colon, the parentheses ( and ) , and the period. The next group of symbols consists of names such as robot and class names, karel and UrRobot . We also use names to refer to instructions, like putBeeper and turnLeft . The third and last group of symbols consists of reserved words. We have already seen a few of these like class
and if
.
Reserved words are used to structure and organize the primitive instructions in the robot programming language. They are called reserved words because their use is reserved for their built-in purpose. These reserved words may not be reused for other purposes in a robot program, such as robot names. To make the reading of programs easier, we may write robot programs using both upper- and lowercase letters as well as the underscore character, but we must be consistent. The robot programming language is case-sensitive, meaning that the use of upper- and lowercase letters in a word must be consistent each time the word is used. For example, import
is always spelled with all lowercase letters. If we use the word Import in a robot program it would refer to something else, perhaps the name of a robot.
Since robot programs need to be read by humans as well as robots, it is helpful to be able to put explanatory material into the program itself. The language therefore permits comments to be inserted into the text of the program. As we have seen in the foregoing program, a comment begins anywhere on a line with the special symbol # (the hash mark). The comment terminates only when the line does. Anything may follow the comment symbol on the same line. The quoted strings immediately following a class or def heading is also a special kind of comment, but these are valid only in those positions. See pydoc in Section 8 of the Appendix.
Every robot program consists of a task to be completed by one or more robots. This main task block is introduced by the form:
if __name__ == '__main__' :
which the language uses to indicate that these instructions can be executed by commands given from your computerÕs operating system. In our metaphor, these are the instructions read by the helicopter pilot. In practice, however, these would be executed if you give your computer the command:
python tester.py
where all of the above program (including the import statements) is in the file named tester.py. See Section 3 of the Appendix for hints on executing robot programs.
If we needed specialized robots to perform various parts of the task, the class declarations of those robots would precede the task list, including the definitions of any new instructions defined in the class declarations. Classes can also be in separate files, called modules in Python. We will go into this in detail in Chapter 3.
The main task block itself normally starts with a list of definitions, called declarations. In the following program we have only one declaration, which declares that the name karel will be used as the name of a robot in class UrRobot . Declarations introduce new names and indicate how they will be used in the rest of the program. We could also declare names for several different robots, even robots of different classes. The declarations of robots can best be thought of as delivery specifications to the factory. They always contain information about how and where the robot should be placed in the world. They don't need to be at the beginning of a task, though we often put them there. They do need to appear before we try to ask them to do anything. After all, we have to deliver a robot before we can ask it to do something. In Python the declaration of a name is just its first use to the left of the assignment (=) operator. Its existence is declared and the name is associated with an initial value.
Every program has one main task block, even when the entire program is spread over separate modules. Most of the statements in the main task block are messages to the robots declared in the declaration list. The one exception here is the delivery instruction, which causes the factory to construct and deliver a new UrRobot named karel to 2nd Street and 2nd Avenue (we always list streets first), facing east, with no beepers in its beeper-bag. When delivered, the robot is set up and ready to receive messages sent to it. Since robots are delivered by the factory in helicopters, we don't need to be concerned about walls in the world that might impede delivery to any corner. The helicopter will be able to fly over them.
We can send messagesto several different robots from the same main task block, so we need to specify which robot is to carry out each instruction. Thus, if we have a robot named karel and want it to move, we send the message karel.move() . This seems redundant here when there is only one robot, but it is required nevertheless. An instruction that causes a robot to perform one of its own instructions, such as move, is known as a message statement. The instruction named in a message statement (move ) is called the message, and the robot (karel ) is the receiver of the message. Messages are the means of getting a robot to execute an instruction.
Execution always begins with the first instruction of the main task block . Robots are not automatically shut down at the end of a program; the turnOff instruction should be used for that purpose. The indenting of the main task block indicates the instructions that will be executed. If we reach the end of the instructions in the main task block and any robot is still on because it hasn't yet executed a turnOff instruction, it means that at least one turnOff instruction has been omitted from the program. This is not an error, but turning off your robots when you are done with them is useful as their appearance will change to show you that they are done.
Observe that the program is nicely indented as well as commented. It is well organized and easy to read. This style of indenting is necessary for the Python system to correctly interpret your program. It is the means by which the Robot Programming Language knows what statements belong with what parts.
The importance of adopting a programming style that is easy to read by humans cannot be overemphasized. Python, fortunately, requires a style that people also find easy to interpret.
We note, for completeness, that instruction statements in a def block (or main task block) can be terminated by semicolons. These will be ignored if present.
When a robot is prevented from successfully completing the action associated with a message, it turns itself off. This action is known as an error shutoff, and the effect is equivalent to receiving a turnOff message. However, turning off is not the only way such a problem could be addressed. An alternative strategy could have the robot just ignore any message that cannot be executed successfully. Using this strategy the robot could continue executing the program as if it had never been required to execute the unsuccessful instruction.
To justify the choice of executing an error shutoff, rather than just ignoring messages in such situations, consider the following: Once an unexpected situation arises-one that prevents successful execution of an instruction-a robot probably will be unable to make further progress toward accomplishing the task. Continuing to execute a program under these circumstances will lead to an even greater discrepancy between what the programmer had intended for the robot to do and what it is actually doing. Consequently, the best strategy is to have the robot turn off as soon as the first inconsistency appears.
So far, we have seen three instructions that can cause error shutoffs: move , pickBeeper , and putBeeper . We must construct our programs carefully and ensure that the following conditions are always satisfied.
We can guarantee that these conditions are met if, before writing our program, we know the exact initial situation in which the robot will be placed.
In this section we classify all programming errors into four broad categories. These categories are discussed using the analogy of a motorist with a task in the real world. It should help clarify the nature of each error type. You might ask, "Why spend so much time talking about errors when they should never occur?" The answer to this question is that programming requires an uncommon amount of precision, and although errors should not occur in principle, they occur excessively in practice. Therefore we must become adept at quickly finding and fixing errors by simulating our programs.
A lexical error occurs whenever the robot program contains a word that is not in its vocabulary. As an analogy, suppose that we are standing on a street in San Francisco and we are asked by a lost motorist, "How can I get to Portland, Oregon?" If we tell the motorist, "fsdt jkhpy hqngrpz fgssj sgr ghhgh grmplhms," we commit a lexical error. The motorist is unable to follow our instructions because it is impossible to decipher the words of which the instructions are composed. Similarly, the robot executing a program must understand each word in a program that it is asked to execute.
Here is a robot program with some lexical errors:
if __name__ == '__pain__' : # misspelled word
karel = UrRobot(2, 2, East, 0) # unknown word
karel.move()
karel.mvoe() # misspelled instruction
karel.pick() # unknown word
karel.move()
karel.turnRight() # unknown word
karel.turn_left # unknown word
karel.move() # karel moves north
karel.move() # karel moves north
karel.putBeeper();
Karel.move() # unknown word
karel.turnleft() # unknown word
The last two errors occur because the robot programming language is case-sensitive. The word turnLeft is not the same as turnleft, nor is karel the same as Karel.
Even if the pilot recognizes every word in a program, the program still might harbor a syntax error. This type of error occurs whenever we use incorrect grammar or incorrect punctuation or indentation. Going back to our lost motorist, we might reply, "for, Keep hundred. just miles going eight." Although the motorist recognizes each of these words individually, we have combined them in a senseless, convoluted manner. According to the rules of English grammar, the parts of speech are not in their correct positions. We discussed the grammar rules for basic robot programs in Section 2.6.2.
The following program contains no lexical errors, but it does have syntax errors.
if __name__ == '__main__' # missing colon
karel = UrRobot(2, 2, East 0) # missing comma
karel.move( # missing parenthesis
karel..move() # extra period
karel.pickBeeper() # incorrect indentation
karel.move(), # misplaced comma
If our program contains syntax errors, the factory will discover them when our program is checked there. It will also discover some, but not all, lexical errors. In both cases, the factory has no conception of what we meant to say; therefore, it does not try to correct our errors. Instead, the factory informs us of the detected errors and doesn't build the robot. This action is not an error shutoff, for in this case the robot never has a chance to begin to execute the program. While discussing the next two categories of errors, we will assume that the factory finds no lexical or syntax errors in our program, so it builds the robot and the pilot delivers it and begins to execute the program.
The third error category is called an execution error. Unlike (some) lexical and (all) syntax errors, which are detected at the factory, the pilot can only detect these errors while the program is running or during a simulation of its execution. Execution errors occur whenever a robot in the world is unable to execute an instruction successfully and is forced to perform an error shutoff. Returning to our motorist, who is trying to drive from San Francisco to Portland, we might say, "Just keep going for eight hundred miles." But if the motorist happens to be facing west at the time, and takes our directions literally, the motorist would reach the Pacific Ocean after traveling only a few miles. At this point, the motorist would halt, realizing that he or she cannot follow our instructions to completion.
Likewise, a robot turns off if asked to execute an instruction that it cannot execute successfully. Instructing a robot to move when the front is blocked, to pickBeeper on a corner that has no beeper, and to putBeeper when the beeper-bag is empty are examples of execution errors, and each one results in an error shutoff.
If a lexical error is detected during execution, such as mistyping the name used to refer to a robot (Karel instead of karel), the program will also be halted and you will need to correct the error and execute it again. The computer system will raise an exception, perhaps an attribute error that will be printed on your computer screen in a console window. This is a kind of lexical error, of course.
The final error class is the most insidious, because pilots, the factory, and robots cannot detect this type of error when it occurs. We label this category of error an intent error. An intent error occurs whenever the program successfully terminates but does not successfully complete the task. Suppose our motorist is facing south when we say, "Just keep going for eight hundred miles." Even though these instructions can be successfully followed to completion, the motorist will end up somewhere in Mexico, rather than Oregon.
Here is an example of an intent error in a robot program: Beginning in the situation shown in Figure 2-4, karel is to pick up the beeper, move it one block to the north, put the beeper down, move one more block to the north, and turnOff .
Figure 2-4 KarelÕs Initial Situation
if __name__ == '__main__' :
karel = UrRobot(3, 2, East, 0)
karel.move()
karel.pickBeeper()
karel.move()
karel.turnLeft()
karel.move()
karel.turnOff()
There are no lexical, syntax, or execution errors in this program. As far as karel and the helicopter pilot are concerned, when the turnOff is executed, everything is perfect. However, look at the task and look at the program. What is the error? The task is to move the beeper one block to the north, yet karel also moved the beeper one block to the east. The intent was a northerly move, but the final result was an easterly move. The program does not satisfy the requirements of the stated task and thus contains an error of intent.
Remember that a robot does not understand the task for which we have programmed it. All that the robot can do is execute the instructions corresponding to messages we have sent it in our program. Thus, there is no way for a robot to know that the program did not accomplish what we intended. Similarly, the pilot has no way to know what we intended. He or she only knows what is actually written in the program itself.
In programming jargon, all types of errors are known as bugs. There are many apocryphal stories about the origin of this term. In one story the term bug is said to have been originated by telephone company engineers to refer to the source of random noises transmitted by their electronic communications circuits. Another story originated with the Harvard Mark I Computer and Grace Murray Hopper, later Admiral. The computer was producing incorrect answers, and when engineers took it apart trying to locate the problem, they found a dead moth caught between the contacts of a relay, causing the malfunction: the first computer bug. Other stories abound, so perhaps we shall never know the true entomology of this word.
Perhaps the term bug became popular in programming because it saved the egos of programmers. Instead of admitting that their programs were full of errors, they could say that their programs had bugs in them. Actually, the metaphor is apt; bugs are hard to find, and although a located bug is frequently easy to fix, it is difficult to ensure that all bugs have been found and removed from a program. Debugging is the name that programmers give to the activity of removing errors from a program.
We are not restricted to using only a single robot to perform a task. We can have as many as we like. We shall see in later chapters that robots can communicate in sophisticated ways. For now, here is a simple task for two robots.
Karel is at 3rd Street and 1st Avenue on a corner with a beeper, facing East. Carl is at the origin facing East. Karel should carry the beeper to carl and put it down. Carl should then pick it up and carry it to 1st Street and 3rd Avenue. The beeper should be placed on this corner. Both robots should face East at the end.
Initial situation Final situation
Figure 2-5. Initial and Final Situations for the Two Robot Task
if __name__ == '__main__' :
karel = UrRobot(3, 1, East, 0)
carl = UrRobot(1, 1, East, 0)
karel.pickBeeper()
karel.turnLeft()
karel.turnLeft()
karel.turnLeft()
karel.move()
karel.move()
karel.putBeeper()
carl.pickBeeper()
carl.move()
carl.move()
carl.putBeeper()
karel.turnOff()
carl.turnOff()
Did you find the intent error here? How can you fix it? Is there more than one way to fix it?
We note for completeness, though we can't use the information yet, that a robot can be delivered with infinitely many beepers in its beeper-bag. If such a robot puts down a beeper or picks a beeper, the number of beepers in the beeper-bag does not change. It is still infinity.
karel = UrRobot(3, 2, East, infinity)
We will use this information in later chapters. It is also possible, though rare, for a corner to contain an infinite number of beepers. Since programs are finite, however, there is no way to put down or pick up an infinite number of beepers.
Robots are examples of programming constructs called objects. Objects have two capabilities: they do things and they remember things. The things that robots do are move, pickBeeper, etc. We will learn some things about remembering in Chapter 4 and later. We ask an object to do something by sending it a message. We can also ask an object something about what it has remembered with a message. Beepers and walls in the robot world are not objects, however. You can't send them messages. As a person, you are something like an object. You can receive messages. You can do things. You can remember things. You respond to the messages you receive.
We refer to Robots using names. These names are called variables. This is because they can vary. A name can refer to different robots at different times, just as in your world, the name karel can refer to different people at different times. Sometimes a robot (and in general, an object) needs to refer to itself. When you refer to yourself you probably use a special "name", like "me." Likewise any robot can refer to itself with the special name self.
A file containing Python code is called a module. Its name usually ends in .py. A folder (directory) of Python modules is called a package. Package and module names are usually written in all lower case. A Python package should contain a file (usually empty) with the name __init__. This is to enable imports.
object
variable
bug
method
message
module
lexical error
syntax error
execution error
intent error
class
self
The purpose of this problem set is to test your knowledge of the form and content of simple robot programs. The programs you are required to write are long but not complicated. Concentrate on writing grammatically correct, pleasingly styled programs. Refer back to the program and discussion in Section 2.6 for rules and examples of correct grammar and punctuation. Each of these problems requires a single robot of the UrRobot class. In each case we assume it will be named karel. This is not required, however, and you are, in general, free to name your robots with other names. Verify that each program is correct by simulating karel's actions in the appropriate initial situation.
Omitted
[1] Ur is a German prefix meaning "original" or "primitive." The pronunciation of ur is similar to the sound of "oor" in "poor."