40. Random escapes

Reeborg the RefurbishedRobot carries inside him some "electronic dice". He can "roll the dice" and decide what to do based on the result. Such a decision, based on an unpredictable result like the roll of dice, is called a random decision. We are going to write a couple of programs that will let Reeborg eventually get out of a maze by making random decisions. Here's the basic algorithm that Reeborg will follow:

We will implement this algorithm using two different type of approaches to dealing with potential problems.

Random escape 1

Our first program will be based on the techniques we have seen up to now. We ask Reeborg to check for the presence of a wall in front and to move only if there is none present. This is sometimes describe as a Look before you leap (LBYL) approach.

G = RefurbishedRobot()
G.set_delay(0) # moving as fast as possible
while True:
    if G.front_is_clear():
        G.move()
        if G.on_beeper():
            G.turn_off()
    r = G.roll_dice()
    if r in [1, 2]:
        G.turn_left()
    elif r in [3, 4]:
        G.turn_right()

We have set the time delay to the minimum value (hence, the fastest speed) as it can take quite a while to find the exit! When Reeborg "roll the dice", 6 different results are possible (the numbers 1 to 6). The example below shows one possible outcome.

random maze solution

Exceptions

To deal with unusual conditions, Python programmers often use "Exceptions". For example, if you try to divide a number by zero, Python will complain in the following way:

>>> x = 1/0
Traceback (most recent call last):
  File "<input>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero

Python responded by "raising" a particular "Exception" (ZeroDivisionError) which resulted in the error message (or Traceback) displayed above. This process of "raising" exceptions is a way that Python program can alert the user about situations with which it does not know how to deal. We can simulate this by using the Python keyword raise

>>> raise ZeroDivisionError
Traceback (most recent call last):
  File "<input>", line 1, in ?
ZeroDivisionError

When we know that a particular exception might be raised, we can "catch" it and deal with it in a way that might make sense. Here's how we do this:

>>> try:
...     x = 1/0
... except:
...     print "You have attempted to divide by zero. This is not allowed."
...
You have attempted to divide by zero. This is not allowed.

Let us use this to write a second program to get Reeborg out of the maze.

Random escape 2

When a problem is encountered by Reeborg (hitting a wall, trying to pick up a non-existent beeper, etc.), an exception is raised. This normally ends the robot program and is "caught" by RUR-PLE to display the appropriate error dialog. If it makes sense, we can write our own program to "catch" this exception and ignore it to allow the program to continue. This is what we do in the program below. This is sometimes describe as a Better to ask forgiveness than permission (BAFP) approach.

G = RefurbishedRobot()
G.set_delay(0) # moving as fast as possible
while True:
    try:
        G.move()
        if G.next_to_a_beeper():
            G.turn_off()
    except HitWallException:
        pass
    r = G.roll_dice(3) # possible values: 1, 2, 3
    if r == 1:
        G.turn_left()
    elif r == 2:
        G.turn_right()

In the example above, we have used different kinds of dice, one with three possible outcome. You can ask Reeborg to use dice with an arbitrary number of possible outcomes to design your own program.

Which approach is preferable?

If an exceptional condition is not expected to occur often, the BAFP approach is preferred. However, if the exceptional condition is expected to occur often (as is the case here), the LBYL approach, that we used in the first example, is recommended.

previousAvoiding repetitions - the important stuff - home - A Robotic Fairy Tale next