CSC 171 
Homework assignment 7

Fall, 1998

Buggles that Make Decisions

When Buggles Go Hurdling!

(Homework assignment based on one by Dr. Frank Turbak of Wellesley College.)

Download the hw7Buggles folder from my download directory on panther. It should contain

In this assignment, we'll teach our Buggles a new Olympic sport: hurdle-jumping. But first, we need to learn how to control Buggles one step at a time.

In class:

Using and Programming TickBuggles:

Compile and run ExampleTickBuggleWorld. It should look just like the BuggleWorlds you've seen until now, except that there's an extra button labelled "tick()", which sends a tick() message to the current Buggle. How that Buggle responds to the tick() message is up to you.
source code with forward(); statementLook at the source code, ExampleTickBuggleWorld.java. It should contain two classes: ExampleTickBuggleWorld, with a run() method that creates an ExampleTickBuggle, and ExampleTickBuggle, with a tick() method that does nothing. Fill in the body of tick() with a forward(); statement. Compile and run the program again, and it should now respond to the "tick()" button by moving forward.
 

buggle turning leftNext, let's replace the "forward();" with two statements: "forward(2); left();"  Compile, run, hit the "run" button, then the "tick" button, and you should see the buggle move forward 2 and turn left.
Hit the "tick" button a few more times and see what happens!  Try some other experiments.
 

Jumping Hurdles:

Close the ExampleTickBuggleWorld project and open the HurdleWorld project. Ignore the first couple of methods and look at the Hurdler class, which should contain an empty tick() method just as before. Fill it in with a forward(); statement, compile and run. You'll probably find that your Buggle is facing a wall, and therefore can't move. But if you move it (by hand) away from the wall, the "tick" button should work just as before until the Buggle hits another wall. (By the way, you can create and remove walls yourself by clicking on the green lines between squares in the BuggleWorld. This will be useful for testing your Buggles.)
buggle jumping too many hurdlesObviously, your Buggle needs to learn how to jump a hurdle. Write a method named "jumpHurdle()", in the Hurdler class, to do this. Replace the forward(); statement in the tick() method with a call to jumpHurdle();. Now compile, run, hit the "run" button, and hit "tick" a few times.
Notice that the Buggle now jumps a hurdle regardless of whether one is there or not. To remedy this, we'll use the Java "if" statement to test whether the Buggle is facing a wall, and jump it only if so. The resulting code looks like
public void tick() {
    if (isFacingWall ()) {
        jumpHurdle ();
        }
    else {
        forward ();
        }
    }
hurdler jumping only when there's a hurdle
 
 

buggle climbing right-hand wallBut there's still a problem: if you keep ticking along, the Buggle will get to the right-hand wall and start climbing it. The Buggle thinks the right-hand wall is a hurdle, so it tries to jump it: turn left, move forward (i.e. north), turn right, move forward (i.e. east), and we can't do this so the Buggle stops in its tracks. The next time, it tries again: move north, head east, and stop. To remedy this, we need to teach the Buggle to detect the "finish line" and stop running. This calls for a method named "atFinishLine()", which returns a boolean that can be used by another "if" statement to do nothing if we're already at the finish line. For purposes of this assignment, any wall two units high or higher constitutes a "finish line", so if we're looking at a wall, we take a step to the left (i.e. north) and we're still looking at a wall, we know we're at the finish line. It's important to make sure that atFinishLine() has no side effects: it doesn't draw anything on the screen, it doesn't have the net effect of moving the buggle, etc. and all it does is answer a yes-or-no question.

    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.
        if (isFacingWall ()) {
            brushUp ();
            stepLeft ();
            if (isFacingWall ()) {
                stepRight ();
                brushDown ();
                return true;
                }
            else {
                stepRight ();
                brushDown ();
                return false;
                }
            }
        else
            return false;
        }
    private void stepLeft () {
        left ();
        forward ();
        right ();
        }
    private void stepRight () {
        right ();
        forward ();
        left ();
        }
Note the use of auxiliary methods stepLeft() and stepRight() to make it clearer what's really going on in the body of atFinishLine().

There's still a certain amount of duplication in the code, which can be cleaned up by introducing a boolean variable:

    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.
        if (isFacingWall ()) {
            brushUp ();
            stepLeft ();
            boolean answer = isFacingWall ();
            stepRight ();
            brushDown ();
            return answer;
            }
        else
            return false;
        }
In addition, of course, we have to use the atFinishLine() method in the body of tick():
public void tick() {
    if (atFinishLine ()) {
        // do nothing
        }
    else if (isFacingWall ()) {
        jumpHurdle ();
        }
    else {
        forward ();
        }
    }
Note that we've also used an "extended" form of the "if...else" statement:
if (first condition) {
    what to do if first condition is true     }
else if (second condition) {
    what to do if first is false, but second is true     }
else if (third condition) {
    what to do if first and second are false, but third is true     }
   .
   .
   .
else {
    what to do if none of the conditions hold
    }

smarter buggleThe result should be a buggle that jumps the hurdles that are there, doesn't jump the hurdles that aren't there, and doesn't climb the wall.

Your assignment:

A Tired Hurdler

hurdler stopped at fourth hurdleIn the file HurdleWorld.java, which you've been working on for a while now, there's also a class named TiredHurdler. It's intended to model a Hurdler who gets tired after jumping a fixed number of hurdles. The instance variable hurdlesLeft keeps track of how much energy the Hurdler has. Your mission is to write a TiredHurdler class that works correctly: if initialized with the number 3, it'll jump 3 hurdles and keep going, but once it reaches the fourth hurdle, it will stop rather than jumping it.
Note that in order to work with the TiredHurdler class, you'll need to change the run() method in the HurdleWorld class: comment out the line that creates a Hurdler, and uncomment the lines that create a (green) TiredHurdler. Note that since TiredHurdler extends Hurdler, all the methods you wrote for Hurdlers are still available for free. You only need to rewrite the method(s) that behave differently.
Hint: I see at least two ways of doing this. One involves writing a new tick() method in the TiredHurdler class, and the other involves writing a new jumpHurdle() method in the TiredHurdler class. In either case, the new method overrides the old one. You may use either approach, or come up with an approach of your own. Turn in your modified copy of HurdleWorld.java.

Finding Your Way Through a Maze

picture of fiona finding the bagel after a long searchNow close the HurdleWorld project and open the FindWorld project. Once again, the "run" button creates a Buggle (this time a Finder named Fiona), but now she's in a maze and must find her way to the bagel. Fortunately, this is a particularly simple kind of maze: a "connected, acyclic graph", which means in practice that if you keep your right hand on the wall, you're guaranteed to eventually find the bagel. Your mission is to fill in the body of the tick() method in the Finder class so that Fiona, and any other Finder, can search through a maze, always keeping her right hand on the wall, until she finds a bagel (you can detect this with the boolean-valued isOverBagel() method), at which point she refuses to go any farther. Be sure to test your program on several different mazes (remember, each time you hit the "reset" button, a new maze is generated randomly for you). You'll probably need to write some auxiliary methods: for example, it might be useful to have boolean-valued methods named canGoRight, canGoStraight, and canGoLeft. (That's a hint!)  Turn in your modified copy of FindWorld.java.



Last modified: Sat Nov 21 16:36:21 EST 1998
Stephen Bloch / sbloch@boethius.adelphi.edu