## 13. Listen to me ... or else ...

While learning how to program may be fun, you should not spend all your time in front of the computer. If it rains, keep reading, otherwise, go outside and play! (Yes, even you grandpa!)

### Making choices

Let me have some fun with the sentence that starts with if.

If it rains,
... keep reading,
otherwise,
... go outside and play!

This is starting to look like a small computer program. Let me write it as though it were a Python program.

    if it_rains():
        keep_reading()
    else:
        go_outside_and_play()

You just learned a new Python keyword, else. So, if it rains, keep on reading; otherwise, you know what to do!

### "I see...", says Reeborg.

In addition to being able to find out if he is standing next to one or more beepers, Reeborg can see if there is a wall in front of him, blocking his way. He can also turn his head to his left or his right and see if there is a wall there. You can ask him to have a look with the following tests:

    front_is_clear()  # True if no wall in front, False otherwise
    left_is_clear()
    right_is_clear()

Let's use the first one to have Reeborg explore his world. We will have Reeborg follow the boundary of his world by asking him to move forward, if there is no wall in front of him, and turn left otherwise. The following simple program is the basis of what is needed:

    if front_is_clear():
        move()
    else:
        turn_left()

    turn_off()

Below is the result of running this simple program in two different situations. If you try it, make sure you don't forget the colon (`:`) after the else keyword.

Now, let's repeat the simple conditional instruction many times to have Reeborg go around his world.

    def move_or_turn():
        if front_is_clear():
            move()
        else:
            turn_left()

    repeat(move_or_turn, 20)
    turn_off()

This, on a small world, give the following end result:

We can make this more interesting by having Reeborg do a "dance" if he can move forward, and put down a beeper if he has to turn. The following program has Reeborg do just that, going only partly around his world:

    def dance():
        repeat(turn_left, 4)
    def move_or_turn():
        if front_is_clear():
            dance()
            move()
        else:
            turn_left()
            put_beeper()

    repeat(move_or_turn, 18)
    turn_off()

Make sure that Reeborg carries enough beepers to do his task! To give Reeborg some beepers to carry, try clicking on the
beepers button.

Notice how the instructions `dance()` and `move()` are aligned after the if statement and indented from it, indicating that they belong in the same block of instructions. The instructions `turn_left()` and `put_beeper()` are similarly aligned, indented from the else statement to which they belong. The result of running the program is indicated below.

Now, what happens if we do not align the instruction `put_beeper()` with `turn_left()`, but align it instead with the else statement, as indicated below.

    def dance():
        repeat(turn_left, 4)
    def move_or_turn():
        if front_is_clear():
            dance()
            move()
        else:
            turn_left()
        put_beeper()

    repeat(move_or_turn, 18)
    turn_off()

Now, the definition of `move_or_turn()` includes a choice if/else resulting in either a dance and a move forward, or a left turn, followed every time by the instruction `put_beeper()`. The result of running this program is indicated below:

As you can see, after every step forward, a beeper has been put down. Each corner now has two beepers: one from the previous move to reach the corner, and one for the left turn after reaching the corner.

Now, suppose we align the `put_beeper()` instruction with the def statement as indicated below?

    def dance():
        repeat(turn_left, 4)
    def move_or_turn():
        if front_is_clear():
            dance()
            move()
        else:
            turn_left()
    put_beeper()

    repeat(move_or_turn, 18)
    turn_off()

Now, `put_beeper()` no longer belongs to the definition as it is not indented to be aligned with other instructions within the definition. It is a single instruction, the first in fact that Reeborg must follow, before repeating the `move_or_turn()` instruction 18 times. The result is the following:

So, as you can see, much information is given to Reeborg through blank spaces (i.e. the indentation of the instructions within blocks). Through practice, you will learn to use this to your advantage and realise that Python allows you to write very readable code by indenting instructions.

### Jumping hurdles

Reeborg has become quite good at jumping hurdles. He now enters races of different lengths: short sprints and long races. He knows that he has reached the finish line when he is next to a beeper. Below, you will find two such race courses; the world files are hurdles1.wld and hurdles2.wld.

Assume that there are no races longer than 20 units. Define an instruction that looks somewhat like the following:

    def move_jump_or_finish():
        if on_beeper(): # end of race
            turn_off()
        else:
            if front_is_clear(): # not finished, and no hurdle to jump
                move()
            else:
                jump_one_hurdle()

with an appropriate `jump_one_hurdle()` instruction, so that, other than definitions, the only instruction that Reeborg needs to follow is
`repeat(move_jump_or_finish, 20)`.

Note that, in the above definition, the code is getting more and more indented as we introduce additional tests.

If only Reeborg could decide on his own ... - - If, else, if, else, ....