CS 161 Homework 8 - Dancing Turtles
Due Fri Apr 19 at 5:00pm
Overview
In this assignment, you will be creating a graphical animation of a turtle dance party. There can be lots of different kinds of dancers at the party--but since they all share some characteristics (e.g., they are all dancing turtles), we can use inheritance to easily create the program and avoid code duplication.
A sample dance party is below: Notice all the different kinds of dancers. In the center are a large group of turtles dancing a pre-specified routine--specifically, the red turtle is dancing the routine and all of the orange turtles are copying him. The black and pink turtles are dancing back and forth across the floor, and the green turtle is just twirling in the corner. Your program will be able to support all of these turtles (and more!)
This assignment should be completed individually. You are welcome to ask for help (either from me or from your classmates), but remember the Gilligan's Island rule!
Objectives
- To practice with inheritance and interfaces
- To practice developing programs without specific method guidance (feel free to ask for help!)
- To continue practicing with ArrayLists and class interactions
- To experiment with other helpful patterns for writing Java programs!
Necessary Files
You will need to download and extract the BlueJ project from the Homework8.zip file. This project will supply you with the following classes:
-
DancingTurtle
This abstract class (we'll talk about what that means) will act as the basis/parent class for your specific kinds of dancers. This class provides a number of methods to help you quickly get turtles to appear and move, such as: themoveForward()
,moveSide()
, andspinRight()
methods. By extending this class, all your dancing turtles will have access to these methods, without you having to write them!Note that as an abstract class, you cannot instantiate this class directly. Instead, you will need to extend it and instantiate its children classes.
You are not required to modify this class; however, if you add new functionality or helper methods that are accessible to all DancingTurtles, you may want to put them in this class. If you make any modifications, be sure to describe them in the README!
Also note that some of the classes and data types used in this class will need to be imported: for exampe, the
Point
class needs to be imported from thejava.awt
package. -
DanceFloor
This class will provide the graphical window and animation system to make your turtles dance. You are welcome to look through its code (we will be talking about these classes soon), but you should not modify it. Check the documentation for methods that you may use: in particular,addDancer()
will let you add turtles to the dance floor, andstartAnimation()
will start them dancing!
Finally, the project contains a README.txt file that you will need to fill out. Remember that you can open this file in BlueJ by double-clicking on the white paper icon!
Details
First, read through all of the assignment carefully. As you do so, think about what kinds of methods you might need, what kinds of variables you may want, and what kinds of functionality you will need.
For this program you will be making many new classes: specifically ones representing specific kinds of dancers. Many of these classes will extend
either DancingTurtle
or each other. I will describe each class you need below:
-
DanceTester
The first thing you should do is make a tester class to test and run your program as you develop it. Your tester should instantiate a
DanceFloor
and then use theaddDancer()
method to add turtles you create to it. CallstartAnimation()
on the DanceFloor in order to start the animation. -
TwirlingTurtle
Let's start by making a very basic dancer to get started: the
TwirlingTurtle
(the green one in the above animation). This class should extendDancingTurtle
in order to use its methods. While you will need to create constructors for the new class, you will not need to declare the instance variables, because you inherit them from the parent! Note that although the parent is abstract, you can re-use code by calling the parent's constructor usingsuper(<params go here>)
.You will need to implement the abstract
step()
method inherited fromDancingTurtle
in order to give the turtle instructions on how to dance (an "abstract" method means that it is listed as something that children need to support, but the details aren't given. We will talk about this more as we go). ATwirlingTurtle
should just turn 90 degrees in place for each step. -
RoutineTurtle
Now you should be getting a feel for how inheritence works, so let's make a more complicated turtle: the
RoutineTurtle
. This turtle is like theTwirlingTurtle
(it should also extendDancingTurtle
) dances/steps by following a specified routine.A routine should be specified as a list of steps (consider: would it be easier to use an array or an ArrayList?). You should specify this list and then pass it as a parameter to the
RoutineTurtle
's constructor.-
But how to specify the list? One option would be to make it a list of Strings (e.g., ["forward", "back", "left", "right"]). However, a cleaner way to do this would be to use constants: for example, you might make a
FORWARD
constant that is anint
with a value of 1, aBACKWARD
constant that is anint
with a value of 2, etc. This makes it fast and easy to check which step you're on: if the step in the list is equal toFORWARD
, then you can moveForward(). Thus means you can write routines as[FORWARD, BACK, LEFT, RIGHT]
, without needing to compare Strings (note that String comparison is much slower than integer comparison).- Moving 25 pixels at a time ended up working well for me, but you can of course change that. Try using a constant or a variable to specify the distance you move, instead of hard-coding it!
- You might even make a separate class (e.g.,
DanceStep
) to contain these constants. Then everyone could talk aboutDanceStep.FORWARD
instead of having to make sure that Strings match perfectly. This kind of "constants class" (where the class just has static constants) is a really helpful patten to use when writing larger programs! - Finally, if you're making a constants class, you might consider using enumerated constants so you don't even need to assign integer values to the constants! Enumerated constants are described in Chapter 5.7 (page 266). This is not required, but might be fun!
Overall, your
RoutineTurtle
should take in a list of dance steps. Then in its step method, you should get the next step in the list and perform that. When you get to the end of the list, go back to the beginning!- Note that you will need to keep track of which step you're on in the list, and then increment this counter each time you take a step. Hint: the modulo operator is a good way to cycle around! Try using math like
i = (i+1)%listSize
.
- Extra Hint: the rest of the program will be slightly easier if you increment the step you're on BEFORE you perform it. So get the next step, then do that step. This means that you'll need to initially start at the -1th step, so that you can start by incrementing to 0 and then do the 0th step.
This turtle can be complicated, so be sure to test him thoroughly! Note that your routine will be specified in the tester and then passed to the turtle.
-
But how to specify the list? One option would be to make it a list of Strings (e.g., ["forward", "back", "left", "right"]). However, a cleaner way to do this would be to use constants: for example, you might make a
-
Leader
The next thing you'll want to do is enable some turtles to lead other turtles (to give the other turtles directions about what dance steps to do). But you'll want multiple different kinds of turtles to be able to lead. As such, you will need to make a
Leader
interface that other classes can implement.Remember that interfaces only have method signatures, not method definitions. And then any class that implements the interface must define those functions. You're specifying that all
Leader
s can perform certain functions (methods)---the interface describes what those functions are.Your interface will likely include the following methods:
-
public Point getLocation() //so the leader can report its position to its follower(s)
-
public Point getDirection() //so the leader can report its facing to its follower(s)
-
public void addFollower(DancingTurtle) //so the leader can add a follower (who it will give steps to).
-
public void removeFollower(DancingTurtle) //so the leader can remove a follower
Note that these methods can be inherited, which counts as being defined (since the child does have that method--even if they just got it from the parent!).
Again, each leader might implement these differently. So the RoutineLeaderTurtle might be able to add multiple followers so it can lead a whole troop, while the TravelingTurtle might only be able to add one special follower.
-
-
FollowingTurtle
In order to have a Leader effectively lead, it will need a follower. So you will need to make a
FollowingTurtle
class that is intended to follow a leader. This class (like the others) should extendDancingTurtle
-
You should include a constructor for this turtle that takes in a
Leader
as a parameter. The follower should then set its position and facing to be immediately opposite of the Leader (75 pixels away from the leader's position was a good number for me). The constructor could also call the Leader'saddFollower()
method to add this follower to the leader!- Note that you may want other constructors as well that do NOT put the follower immediately in front of the leader---such as for making the line dancing turtles shown in the animation.
- This turtle will need to define the
step()
method (why?), but this method shouldn't do anything!FollowingTurtle
s only move when ordered to by their leader; they do not step on their own!
Be sure and test that the follower shows up on the dance floor and doesn't do anything without a leader.
-
You should include a constructor for this turtle that takes in a
-
RoutineLeaderTurtle
Now that you have a follower, you should make a leader class to lead them! In particular, you might start with the
RoutineLeaderTurtle
who can lead multiple followers in a routine (you can also start with theTravelingTurtle
described below). This class should extendRoutineTurtle
(since it will also do a Routine), but will also implement theLeader
interface.- Note that you will need to make new constructor(s) for the RoutineLeaderTurtle that call the parent's constructor(s) using
super()
. - You will need to implement all of the methods in the
Leader
interface. In particular, theaddFollower()
andremoveFollower()
methods should add followers to a list of followers who are given orders, so you can lead a whole troop. -
In the
step()
method, yourRoutineLeaderTurtle
should first do the routine exactly like its parent! You should do this by calling the parent's step() method. This will allow you to reuse the parent's method and functionality without needing to rewrite code--instead just extending that functionality.- After you have done a step (using the parent's method), you should go through your list of followers and tell each of them to take that same step. You may consider abstracting the "given a command, do a step" functionality into a separate helper method to avoid code duplication.
You can test this turtle by making followers and checking that they all dance in sync!
- Note that you will need to make new constructor(s) for the RoutineLeaderTurtle that call the parent's constructor(s) using
-
TravelingTurtle
The
TravelingTurtle
is a turtle who leads its dance partner across the floor, turning around when they get to the far side (the black turtle in the above graphic). This turtle should extend DancingTurtle and implement the Leader interface.- Start by making the basic constructors and filling in the required methods (just like with the previous turtles); test that you can make your TravelingTurtle show up!
- Once that works, fill in the
step()
method to have the turtle walk across the floor. When it hits the other side (which you'll know because themoveFoward()
method will return false), have it start walking backwards! - The turtle will also need to give instructions to the follower. If you don't have a follower, you might just stand still (or travel on your own; either way!) In your
TravelingTurtle
's step() method, you will also need to tell your follower to move in a certain way by calling the appropriate methods on that object. For example, if you want your follower to step forward, you will call themoveForward()
method on the follower. Note that you can't just call the step() method (why? not) -
In order to get your very own Fred & Ginger to waltz across the floor, consider the following algorithm:
if I'm walking forward tell the follower to step backwards if the partner cannot step backwards change movement direction otherwise step forward after the follower otherwise if I'm walking backward step backwards if I cannot step backwards change movement direction otherwise tell the follower to step forward after me
You can also make further changes to this: can you avoid pausing at the edges of the wall? Can you get the pair to spin around as they walk (like a in a Viennese waltz?
Some final notes:
- Be sure and test all your turtles! They should be able to dance and play without any problems :)
- Be carefully about using good Object Oriented style: keep in mind coupling and cohesion, and try to avoid code duplication. Inheritence means that we can re-use code easily, but we want to make sure that we're only giving functionality to classes that should have it (i.e., don't put everything inside DancingTurtle, because a DancingTurtle can't do everything!). Remember that calling parents' methods is a good thing!
- Include a Javadoc class comment on each of your classes (including the tester!) You should also include comments on each method. Documentation is important!
- Remember to include lots of inline comments that explain your code (the why, not the what). This is a big program, and comments will help both you and me to not get lost.
Timeline
This assignment is sizable, likely bigger and harder than the previous two. There are a lot of parts (though each part may be somewhat small). GET STARTED EARLY so you don't run out of time!
- You should get your first turtle (the Twirler) implemented on Day 1--make sure you can do basic inheritance!
- The RoutineTurtle will likely take a couple days, but it should definitely be done by Mon 04/15.
- Adding the Leader, FollowingTurtle, and RoutineLeaderTurtle shouldn't be too difficult by this point. If you can get ahead over the weekend, you should be able to get them done by Wed 04/17
- You can then add the TravelingTurtle and any extensions, as well as clean up documentation and stuff, by the due date on Fri 04/19.
Submitting
Check and double-check that your program works, that your code is commented, and that your name is in the class comment at the top of your program!
Be sure to complete the provided README.txt file with details about your program.
Upload the entire BlueJ project to the Hwk8 folder on the submission folder on hedwig. Make sure you upload your work to the correct folder!. This assignment is due at 5:00pm on Fri Apr 19.
Be sure to include a tester class that shows off all your dancers!
Extensions
As always, there are many extensions to this assignment. Completing them can earn you up to 5 points of extra credit.
- The provided "turtles" are pretty simple artistically--they actually look more like bugs. You might change the draw() method of the DancingTurtle class to draw more interesting turtles. Remember that turtles can face in one of four directions, which should be clear from your drawing!
- You might add further custom turtles: I mentioned the Viennese waltz before, but you also might make a traveler that circles the room, or maybe does some other crazy kind of dance (that ISN'T just specified through a routine!)
- Can you make the turtles dance in a conga line? You might have a CongaTurtle class that is both a Leader AND a Follower! Notice that followers won't turn at the same time as the leader, but instead will turning a step later.
Grading
This assignment will be graded on approximately the following criteria:
- You have a working TwirlingTurtle [5%]
- You have a working RoutineTurtle, who follows a specified routine [20%]
- You have a Leader interface that is used by other classes [5%]
- You have a working FollowingTurtle that can position itself opposite the leader [10%]
- You have a working RoutineLeaderTurtle who can lead multiple followers in the routine [15%]
- You have a working TravelingTurtle who will lead its partner across the dance floor [15%]
- You have a tester class that shows off all your dancers! [5%]
- Your code is carefully documented, with full Javadoc methods and inline comments [10%]
- Your code adheres to proper style guidelines. This means that variables are given descriptive names, tabs and braces are lined up, local variables aren't specified in the fields, etc. It also means that you've avoided code duplication, and that your class hierarchy is properly organized. As always, if you have any questions about good style, don't hesitate to ask! [10%]
- You have completed the included README.txt file [5%]