Consider the following world
Does the program written previously work with it? Try it!
As you probably guessed, if you didn't try it (you should, really!), it does not. To make it work, we need to replace the if we just added by a while. Try it! Make sure to save it.
We seem to have designed a program that works in all situations we are likely to encounter. This program, before we forget, is to allow Reeborg to explore his world, going around once. While the program is rather short, and its structure should be clear at this point, it might not be so obvious to someone who just happened to see it for the first time. It's probably a good idea either to add comments and/or to introduce more meaningful words. Let's start by adding comments, somewhat more verbose than we think we might need.
# we define a useful instruction def turn_right(): repeat(turn_left, 3) # we mark the starting point by putting down a beeper put_beeper() # We then find a clear direction and start moving. while not front_is_clear(): turn_left() move() # We know we have gone around the world # when we come back to the beeper we put down. while not on_beeper(): if right_is_clear(): # keep to the right turn_right() move() elif front_is_clear(): # move following the right wall move() else: # follow the wall by turning left turn_left() turn_off()
While this sort of clarifies our intent for each instruction, it is not really that helpful in summarizing the method (also known as the algorithm) used in solving the problem. Therefore, these comments might not be as helpful to another reader as we might have wished. Reading over the comments, we note that the program has two parts:
Let's rewrite this program so that these two parts become clearer, and writing the comments differently.
# This program instructs Reeborg to go around his world # counterclockwise, stopping when he comes # back to his starting point. def turn_right(): repeat(turn_left, 3) def mark_starting_point_and_move(): put_beeper() while not front_is_clear(): turn_left() move() def follow_right_wall(): if right_is_clear(): turn_right() move() elif front_is_clear(): move() else: turn_left() found_starting_point = next_to_a_beeper # beeper marks the starting point. #=== End of definitions; begin solution mark_starting_point_and_move() while not found_starting_point(): follow_right_wall() turn_off()
Isn't this clearer? Now, suppose that each corner has a beeper on it at the start. We could then choose to mark the starting point by removing a beeper. We would need to make some small changes in the definitions, but the solution as such would not need to be changed.
Change the program you just wrote to remove the put_beeper() instruction. After saving it, try this slightly modified program with the following hurdle race (file: hurdles3.wld).
Surprise! Other than finishing facing in an unusual direction (perhaps bowing to the crowd after winning), the program we just wrote can solve the hurdle problem. It also works with the uneven hurdle (file: hurdles4.wld) illustrated below - which the program we wrote before for jumping over hurdles could not handle!
Try the same modified program again with the maze problem we introduced in one of the first lessons (file: maze1.wld), as illustrated below.
As you will see, our simple program can find the exit to this maze! Amazing!
We started with a simple problem to solve (going around a rectangular world) and, by improving little by little (also called stepwise refinement), we manage to write a program that could be used to solve many other apparently unrelated problems. At each step, we kept the changes small, and made sure we had a working solution, before considering more complex problems. We also used more descriptive names for parts of the algorithm which made the program easier to read and, hopefully, to understand. This is a strategy you should use when writing your own programs: