Karel and Company - More Robots

Programming with Karel J Robot - Part 3 of 4

Welcome to part three of Programming with Karel. In this episode we are going to start controlling more than one robot and have a look at how robot names work. But first I’ll make a comment.

Just making a comment here

Now that we’re getting familiar with how the robot world works, let’s start to do things in a more orderly fashion. Listing 1 is a solution to the double-decker squares problem from the previous article:

Fig. 1 - The double-decker squares problem

Figure 1

There is a new part of the syntax introduced here - the double slash ‘//’ that marks a “comment”. In Java anything from a double slash ‘//’ to the end of the line is simply ignored by the compiler. Remember that computer programs are mainly for people to read, so the double slash allows you to make free-form remarks in the code to help make a program easier to understand. A helpful feature of BlueJ is that comments appear in a different colour, so it’s easy to tell what’s comment and what’s code. Handy, isn’t it?

Listing 1.

import kareltherobot.*;

public class Example03 implements RobotTask
{
  public void task()
  {
    World.reset();

    World.setTrace(false);
    World.setVisible(true);

    // make a new robot
    SquareMaker karel = new 
          SquareMaker(1, 2, East, 8);

    // make the first square
    karel.move();
    karel.makeSquare();

    // move into position
    // for the next square
    karel.turnLeft();
    karel.turnLeft();
    karel.turnLeft();
    karel.move();
    karel.turnLeft();
    karel.turnLeft();
    karel.turnLeft();

    // start the second square
    karel.makeSquare();
    karel.move();
  }
}

But Listing 1 is a bit disappointing after our last instalment where we gave so much attention to removing unnecessary repetition. Now that we need to move the robot into position for the second square we end up with more repetition! Really, this is most annoying.

It’s time to get some teamwork going.

Fun with dick and jane

Listing 2 shows a team of two robots making the two squares. The first, jane, starts at the corner of 1st and 3rd, makes a square then moves aside one space. The other, dick, starts at 5th and 3rd but otherwise does the same job as jane. That’s all there is to making multiple robots. Knowing this, you could now make as many robots as you like simply by thinking up a unique name and calling new SquareMaker(); for each one.

Listing 2.

import kareltherobot.*;

public class Example03 implements RobotTask
{
  public void task()
  {
    World.reset();
    World.setTrace(false);
    World.setVisible(true);

    // make a new SquareMaker
    SquareMaker jane = new
      SquareMaker(1, 3, East, 4);

    // jane makes the first square
    jane.makeSquare();
    jane.move();

    // make another new SquareMaker
    SquareMaker dick = new
      SquareMaker(5, 3, East, 4);

    // dick makes the second square
    dick.makeSquare();
    dick.move();
  }
}

And here we learn the first new thing about robot names - you can call your robots practically anything. In fact, the name of a robot doesn’t need to be a real name or even a real word. There are a few simple rules about robot names, but for the moment we’ll just use ordinary human names.

Reduce, reuse, recycle

There is something else you need to know about robot names. Unlike your name which is yours to keep, robot names are more like stick-on labels that can be transferred between robots as required. Listing 3 will help to illustrate.

Listing 3.

import kareltherobot.*;

public class Example03 implements RobotTask
{
  public void task()
  {
    World.reset();
    World.setTrace(false);
    World.setVisible(true);

    // make a name called jane
    SquareMaker jane = null;

    // make a SquareMaker robot
    // and call it jane
    jane = new SquareMaker(1, 3, East, 4);

    // jane makes the first square
    jane.makeSquare();
    jane.move();

    // make another SquareMaker
    // and call it jane also
    jane = new SquareMaker(5, 3, East, 4);

    // the new robot, also called 
    // jane, makes the second square
    jane.makeSquare();
    jane.move();
  }
}

Notice some subtle differences. Firstly, we make jane as a SquareMaker-style name, but we don’t give it a SquareMaker robot straight away:

// make a name called jane
SquareMaker jane = null;

Use the word null to show that jane isn’t a name for anything in particular (yet).

Next we use the name jane to refer to something - a brand new SquareMaker robot:

// make a SquareMaker robot
// and call it jane
jane = new SquareMaker(1, 3, East, 4);

See the difference? In previous examples we did both steps on one line, that is make a name and give that name to a new robot. Something like this:

SquareMaker jane = new SquareMaker(1, 3, East, 4);

Then it’s all the same as before until we get to the second robot - and dick doesn’t make an appearance:

// make another SquareMaker
// and call it jane also
jane = new SquareMaker(5, 3, East, 4);

It looks like jane can do it all alone. But note carefully: although the name is the same, there are still two separate robots here.

Beer and Robots

Have you ever been to a crowded party or BBQ where there’s heaps of people you don’t know? Or worse, heaps of people you do know but can’t remember their names? In these circumstances, I use my old fallback: “Mate”. As in, “Mate, can you pass me a beer?” It’s not a bad strategy - I don’t need to know the real name of the man by the fridge because “Mate” does the job quite nicely. It doesn’t even need to be the same person. If I come back later and there’s someone different by the fridge, “Mate, can you pass me a beer?” will still work!

A very similar thing is happening with our robots, except the question is jane.makeSquare();. Just like getting a beer at a BBQ, it doesn’t matter that the second time we ask the question jane refers to a different robot.

Beer drinking may be the perfect pastime, but in this case it doesn’t make a perfect metaphor: When I go back to the fridge a third time, the man who gave me my first beer has returned. I can repeat “Mate, can you pass me a beer?” and (provided he’s not getting sick of me), he’ll pass me another beer. But with the robots, once I’ve used the name jane to refer to the second robot, I can’t use it to refer to the first robot anymore. I can’t go back to the first robot and say jane.makeSquare(); because jane now refers to the second robot. In fact, once I’ve moved the name jane onto the second robot I can no longer refer to the first robot at all.

Fig. 2 - the name jane refers to different things as the program progresses.

Figure 2

Cup-and-ball

In fact, that last statement is not entirely true - it is possible to refer to the first robot again, provided that it still has a name. Let’s have a look at how robot names can be swapped around. The following explanation will make more sense if you compile Listing 4 and watch it carefully while it runs.

Listing 4.

import kareltherobot.*;

public class Example03 implements RobotTask
{
  public void task()
  {
    World.reset();
    World.setTrace(false);
    World.setVisible(true);

    // make two new robot names
    SquareMaker jane = null;
    SquareMaker dick = null;

    // make robot 1
    // and call it jane
    jane = new SquareMaker(1, 3, East, 4);

    // make dick refer to robot 1
    dick = jane;

    // dick makes the first square
    dick.makeSquare();

    // make robot 2
    // and call it jane
    jane = new SquareMaker(5, 3, East, 4);

    // use jane to make 
    // the second square
    jane.makeSquare();
    jane.move();
    jane.move();

    // make jane refer 
    // to robot 1 again
    jane = dick;

    // use jane to tell 
    // robot 1 what to do
    jane.move();
    jane.move();
  }
}

This time we start out with two unallocated robot names, jane and dick. As in the previous example, we make a new robot and use the jane name to refer to it.

Then we get to

dick = jane;

By now you’ve probably got used to the idea that the equals sign is used to give a name (on the left) to a robot (on the right). Although there are robot names on both sides, this line works in exactly the same way - it gives the name on the left (dick) to the robot on the right. And the robot on the right is the same robot to which the label jane is given - the one that is facing east at the corner of 1st and 3rd, holding four beepers. This line makes both labels - jane and dick - point to the same robot.

We prove that both names refer to the one robot in the next line, where we tell dick to make the square - and it does just that.

Then we make a new robot and give it the name jane. The situation now is that jane refers to the second robot while dick still refers to the first robot. So the next three instructions to jane are carried out on the second robot:

jane.makeSquare();
jane.move();
jane.move();

This is exactly what we want to happen.

Following the discussion above about

dick = jane;

we can confidently predict the result of

jane = dick;

This time the robot name on the left is jane and it is being given to the robot on the right - the robot refered to by dick, that is the first robot. So jane and dick are both labels for the same robot again. Knowing this, we are sure that the last two instructions

jane.move();
jane.move();

act on the first robot, not the second.

If you’ve been able to follow this cup-and-ball routine, you’ll notice that the second robot no longer has a name allocated to it, so it can’t be recovered and referred to again.

Fig. 3 - swapping names around

Figure 3

So the key point here is: if you need to send instructions to a robot then it must have at least one name left that refers to it.

A task for you.

In Listing 4, when we gave the command jane = dick; we transfered the name jane from robot 2 back to robot 1, leaving robot 2 without a name and beyond reach. Can you think of a way of swapping the robots that jane and dick refer to without leaving any robots “orphaned”? In other words, start with jane referring to robot 1 and dick referring to robot 2 but end with jane referring to robot 2 and dick referring to robot 1.

Wrap up

In this episode we have covered the following points:

  • how to make and control several robots at once
  • robots can have more than one name
  • a robot name can only refer to one robot at a time
  • it is possible to make a robot name refer to different robots at different times
  • it is not possible to give instructions to a robot that doesn’t have at least one name

Next time

In the next astounding episode we will stop making boring squares and branch out to other shapes.

First published: PC Update Dec 2003 (online version updated)