CS 161 Lab #5

February 15th

Goals:

This week we'll get practice with object references and classes that "manage" other objects. We'll add an extra layer of complexity though, by working with classes that manage other classes that manage other classes! The class diagram below summarizes the plan: We will add some code to the TurtleMob class, which keeps track of a couple of Turtle instances in much the same way as a CircleDrawer managed a pair of Circle objects. But since each of our Turtle instances contains a Circle, we actually have a three-level hierarchy. To help you keep track of the fields and methods in each of the classes, I've generated the documentation for you.

Documentation

  1. Before you download this week's lab project, take a minute to look at the documentation. Explore each of the three classes listed in the pane on the left. See if you can get an overview of the fields in each of the classes, and the "getters" that you could use to get their values. For example, what sorts of getters are there in the Circle class? How about for the Turtle class? This will be valuable information in later parts of the lab!
  2. Now download the TurtleMob_Lab project and extract its contents, then start BlueJ and open the project. The Turtle code is basically the same as the solution to the Turtle homework assignment but, as you've hopefully noticed already, with some "getter" methods to help us peek at its state. I've left some methods partially defined in Turtle and TurtleMob that you'll fill in later.

Extending the Turtle Class:

  1. Your first task is to add a copy constructor to the Turtle class. Remember that the job of a copy constructor is to "clone" an existing object. In this case, we want a constructor that takes a reference to another Turtle object, and sets the current Turtle's state to be identical to the existing Turtle. This means making sure that "our" xDirection, yDirection, and distance fields all hold the same values as the other Turtle's fields do, but don't forget about the Circle field, shell. We need to make sure that our new Turtle instance has its own, separate Circle object, but that "our" circle has the same state as theirs. (Hint, there's already a copy constructor in the Circle class. See if you can use that to help you out here.)
  2. Test out your code before you proceed to make sure your copy constructor works. For example:
  3. Now finish the equals method in the Turtle class. We'll declare two Turtle instances to be the same if the xDirection, yDirection, and distance values match, and their Circle objects are at the same locations. Think carefully about how to retrieve all of the information you need. How do you compare "our" xDirection to theirs? How do you compare our Circle's x position to their Circle's x position?
  4. Test your equals method before proceeding: Create a Turtle and ask it if it's equal to itself. Then try creating a second identical Turtle and verify that equals finds them to be the same. Move one of the Turtles and try again to make sure equals now detects that they're not the same.

Building the TurtleMob

  1. Open the TurtleMob class and take a look around. You'll discover pretty quickly that it's not much of a mob. The class only manages two Turtle objects, but it can ask them both to move in various ways. Go ahead and create a TurtleMob instance and use advance to move it — that much should be working already.
  2. A single TurtleMob isn't very big, but we can create a secret weapon: We can write a copy constructor that can set up a new TurtleMob object that looks just like an existing Mob. We could use such a constructor to "clone" an existing Mob and quickly double our numbers. A couple more copies and we're starting to look more like a mob of turtles! Finish the copy constructor in TurtleMob. Note that we only have two fields to worry about, but that each of those fields is pretty complex — each is a Turtle instance, which has information about the direction it's facing and how far it moves, but also contains a complete Circle object, which then has its own state. Your copy constructor needs to make sure that our new pair of Turtles is identical in every way to the existing pair of Turtles. (Hint: Don't forget that we already added a copy constructor to the Turtle class! Think about how you can use that here to make your life easier.) As always, test your code before proceeding.
  3. Just to be thorough, let's add an equals method to the TurtleMob class as well. It should only return true if our first turtle is an exact match for their first turtle, and our second matches their second turtle. (If only we had some easy way to test Turtles for equality... Wait, we do!)
  4. Before calling it quits on TurtleMob, finish the definition of sameSpot(). It's supposed to return if both of the turtles in a given Mob are at the same position. (We're not comparing one Mob to another Mob, we're comparing "comet" to "cupid" here.)

The Debugger

  1. Take a moment to explore the debugger so you have a better sense of what it can do for you. For example, try setting a breakpoint in TurtleMob's advance method. (Double-click on the left margin of the screen where the stop sign is shown below to set the breakpoint.) Then create a TurtleMob like you normally would and call its advance method. The execution should pause before running the selected line of code. Experiment with the "step" and "step into" buttons. Do a "step" once, for example, and verify that comet moves forward. On the next one, try a "step into" and see what happens.

Extras

If time permits, try some of the following exercises:


Brad Richards, 2024