CS111 Lab 5 Solutions


The working code for the following solutions can be downloaded from:

http://cs111.wellesley.edu/~cs111/download/lab_solutions/lab5_solutions.

HurdleWorld Solution

Exercise 1: Running the Hurdles

In HurdleWorld, a hurdle is a 1 square-high wall; the finish line is the right-hand grid wall. A Hurdler object, which starts in position (1,1) runs a race by moving EAST, jumping over all the hurdles, and stopping at the finish line. The race may be decomposed into the possible situations which may occur as the Hurdler runs, and the action to take for that particular situation:

  1. If the Hurdler is at the finish line, stop.
  2. If the Hurdler is at a hurdle, jump over it.
  3. Otherwise, move forward one space.

The HurdleWorld.java file provides the following skeleton:


   class Hurdler extends TickBuggle {
      public void tick() {

         // Flesh out this skeleton

      } // tick()

     public boolean atFinishLine() {

        // Flesh out this skeleton
        return /* true or false */ 

     } // atFinishLine()

     public void jumpHurdle() {

        // Flesh out this skeleton

    } // jumpHurdle()

   } // class Hurdler

Basically, the tick() method consists of an if-else construct which addresses each of the possible situations listed above:


  public void tick() {

    if (atFinishLine()) {
       // Do nothing
    } else if (isFacingWall()) {
       jumpHurdle();
    } else {
       forward();
    }

  } // tick()
Another way to write the tick() method uses the fact that nothing in the method is executed after a return statement is reached. You can also eliminate the curly braces when there is only one statement in an if or else clause.

  public void tick() {

    if (atFinishLine()) return;

    if (isFacingWall())
       jumpHurdle();
    else 
       forward();

  } // tick()

The atFinishLine() method is used by tick() to test if the Hurdler is at the finish line. The isFacingWall() method may be used to determine if the buggle is facing a wall; if so, the Hurdler must distinguish between whether the wall is a hurdle or the final wall. To do this, the Hurdler must move up one square and look to see whether it is still facing a wall. If so, it is the finish line, and the method should return true; otherwise, it should return false. In either case, an invariant is applied such that the Hurdler must be restored to its original position and heading before exitting the method.

In this solution, a local boolean variable result is declared at the start of the method. It is not immediately assigned a value, but is used later on to temporarily hold the value of true or false indicating whether or not the finish line has been reached. This local variable is used specifically because of the invariant which requires the Hurdler to be returned to its original position and heading after the result is determined.


  public boolean atFinishLine() {
    /*
     Return true if buggle is facing wall (as opposed to hurdle) and false otherwise.
     Should leave buggle in same position and heading as when it starts.
     Should not leave any marks behind.
    */

    boolean result;

    if (isFacingWall()) {

       brushUp();
       left();
       forward();
       right();

       result = isFacingWall();

       left();
       backward();
       right();
       brushDown();

    } else {
       result = false;
    }

    return result;

  } // atFinishLine()
Here is a another way to write the same thing:

  public boolean atFinishLine() {

    boolean result = false;

    if (isFacingWall()) {

       brushUp();
       left();
       forward();
       right();

       result = isFacingWall();

       left();
       backward();
       right();
       brushDown();

    } 

    return result;

  } // atFinishLine()

The jumpHurdle() method is simply the steps taken by the Hurdler is go up the hurdle, over it, down the opposite side, and finish facing EAST:


  public void jumpHurdle() {
   
     left();
     forward();
     right();

     forward();
      
     right();
     forward();
     left();
   
  }

Exercise 2: HighHurdler

The cool thing about writing code for the HighHurdler (now the hurdles can be either of height 1 or height 2) is that the tick() method can remain unchanged! Only jumpHurdle() and atFinishLine() need to be tweaked a bit.

For jumpHurdle(), we introduce a new boolean variable highhurdle, which is true if the hurdle is 2 cells high, and false otherwise. Then we use highhurdle to jump the appropriate height. Here is the new jumpHurdle(): (new code in red)


  public void jumpHurdle() {

  boolean highhurdle = false;

  left();
  forward();
  right();
  
  if (isFacingWall()) {
     highhurdle = true;
     left();
     forward();
     right();
  }
  
  forward();
  right();
  
  if (highhurdle) {
     forward(2);
  } else {
     forward();
  }

  left();

}  // jumpHurdle()

Now, we also have to adjust atFinishLine(), so that the buggle can determine whether or not it is actually at the finish line! Since hurdles can be of height 2 now, the only way to make sure the buggle is at the finish line is to move the buggle up 2 cells (instead of just one cell) and see if there is a wall in front. So the only change to the code is the forward(2) and backward(2), shown in red below:


  public boolean atFinishLine() {
  /*
   Return true if buggle is facing wall (as opposed to hurdle) and false otherwise.
   Should leave buggle in same position and heading as when it starts.
   Should not leave any marks behind.
  */

  boolean result;

  if (isFacingWall()) {
     brushUp();
     left();
     forward(2);
     right();

     result = isFacingWall();

     left();
     backward(2);
     right();
     brushDown();
  } else {
     result = false;
  }

  return result;

  }

Exercise 2: TiredHurdler

The TiredHurdler is a Hurdler that can jump no more than a specified number of hurdles. The constructor method for TiredHurdler takes an integer that is the maximum number of hurdles the buggle will jump.

For instance, new TiredHurdler(3) creates a buggle that will jump no more than three hurdles. If it encounters a fourth hurdle, it will stop moving.

Here is the skeleton for a TiredHurdler class in HurdleWorld.java:


  class TiredHurdler extends HighHurdler {
     private int hurdlesLeft;

     public TiredHurdler(int hurdlesLeft) {
        this.hurdlesLeft = hurdlesLeft;
     } // TiredHurdler()

     public void tick() {

        //Flesh this skeleton out

     } // tick()

  } // class TiredHurdler

The class has an integer instance variable hurdlesLeft that keeps track of how many more hurdles the buggle is willing to jump. The constructor method for TiredHurdler initialize this instance variable to the number supplied when the instance is constructed. When a TiredHurdler runs the course, it should decrement this instance variable every time it jumps a hurdle, and refuse to jump a hurdle when this instance variable contains 0.

The solution is very similar to exercise one, but with an additional condition to test for and action to take:

  1. If the Hurdler is at the finish line, stop.
  2. If the Hurdler is at a hurdle, and hurdles are left (i.e. hurdlesLeft > 0), jump over the hurdle and decrement the number of hurdles left (i.e. hurdlesLeft = hurdlesLeft - 1)
  3. If the Hurdler is at a hurdle and no hurdles are left, stop.
  4. Otherwise, move forward one space.

This can be expressed with the following tick() method:


  public void tick() {
     if (atFinishLine()) {
        // Do nothing
     } else if ((hurdlesLeft > 0) && isFacingWall()) {
        jumpHurdle();
        hurdlesLeft = hurdlesLeft - 1;
     } else if (isFacingWall()){
        //do nothing
     } else {
        forward();
     }
  } // tick() 
And here's another version:

  public void tick() {
     if (atFinishLine()) return;
     if ( (hurdlesLeft > 0) && isFacingWall() ) {
        jumpHurdle();
	--hurdlesLeft;
	return;
     }
     if (!isFacingWall())
        forward();
  } // tick()