CPSC 225 Intermediate Programming Spring 2025

Lab 9: Inheritance

Due: Thu May 1 at the start of lab

Introduction

The goal of this lab is to gain some experience with inheritance and polymorphism, including designing inheritance hierarchies and deciding on when to use abstract classes and interfaces.

About Due Dates

Labs are due at the start of lab on the date listed.

To be eligible for revise-and-resubmit, you must turn in something by the due date. Late work and extensions are generally not accepted/granted; see the posted late policy for more information.

Note that there will be an abbreviated revised-and-resubmit for this assignment. There is not time to grade and return work for a resubmit, but there will be an opportunity to discuss your lab in office hours during reading period and resubmit after that. The resubmit will be due by the final end-of-semester deadline at the end of the final exam timeslot.

About Collaboration and Getting Help

You may work with a partner if you wish. Both partners must actively contribute to the solution! You only need one handin for the group — be sure to put both teammates' names in every file.

Otherwise you may get help but you may not use other resources (friends, neighbors, websites, ChatGPT, etc) to produce answers. See the posted policy on academic integrity for more information.

Handin

To hand in your work:


Preliminaries

Rabbit Hunt

rabbit hunt screenshot

A fox (the red circle) is chasing a rabbit (the brown circle) in a field. The field contains a number of bushes (green squares), and is completely surrounded by a large hedge made up of a bunch of bushes. The hedge is impenetrable, so no animals can leave the field. The bushes obstruct the view of both rabbit and fox, so they may or may not be able to see each other at any given moment. There are also some sloths (gray circles), which are mostly sleeping ("Zz") but occasionally wake up (no "Zz") and make a move before going back to sleep. The sloths don't do much (they aren't interested in the fox and rabbit, and the fox and rabbit aren't interested in them), but they do obstruct the view of the rabbit and fox (which may work to the rabbit's advantage). And beware! There may also be some werebushes, which look like bushes most of the time but occasionally turn into animals and move around.

If the fox catches the rabbit, the fox gets lunch (and wins). If the rabbit can evade the fox for 100 turns, the fox gives up in disgust and leaves (and the rabbit wins). Will the rabbit escape?

Your task is to find out, by creating a program to simulate the chase just described. Inheritance and polymorphism will be essential for reducing the amount of code you need to write!

This is based on an assignment by David Matuszek.


Provided Code and API Documentation

You have been provided with several classes:

You've also been provided with a JAR file containing compiled versions of two classes:

API documentation for the provided classes can be found below:

Finally, there's a demo so you can see how things should work. More information about running it is in the Setup section below.


Exercises

Setup

To run the demo, locate rabbithunt-demo.jar under "Referenced Libraries" and choose Run As → Java Application. Use 'g' (for "go") to start the simulation, 'p' to pause, 's' to step a single step at a time, and 'r' to reset the current chase.

Tasks

Note: it is very important that you name your classes and methods as directed below, and that you have the right header for each method. (i.e. the right types of parameters in the right order, and the right return type) If you don't, the provided code will not work! (You'll get compiler errors and possibly program crashes with NoSuchMethodError exceptions.) Start on the lab early enough so that you have time to ask if you run into problems you can't fix.

Second note: it is very important that you organize the functionality of your code correctly. Pay attention to what the language is telling you! Remember to be a lazy programmer — put functionality as high as possible in the inheritance hierarchy so that you aren't repeating things. If you get the organization incorrect, you may notice problems with the fox (e.g. the fox doesn't appear). Start on the lab early enough so that you have time to ask if you run into problems you can't fix.

A third note: You should include the lines

  import javafx.scene.paint.*;
  import javafx.scene.canvas.*;

at the very beginning of every file where drawing is involved.


Exercise #1: Things, Bushes, and Animals

Note that while these specifications describe what functionality (instance variables and methods) each kind of thing should have, you'll need to decide where each instance variable and method should be declared, what methods and classes should be abstract and what methods should have bodies, if anything should be an interface, and what should be private/protected/public. Make use of inheritance! (Pay attention to the language — if something applies to animals, for example, don't repeat that element for each particular kind of animal.) Also make use of super and this as needed to reuse code instead of repeating things.

Additional notes:


Exercise #2: Creatures and Werebushes

  • Write Creature and Werebush as described below. You may also need to make modifications to your code from #1.

Note that while these specifications describe what functionality (instance variables and methods) each kind of thing should have, you'll need to decide where each instance variable and method should be declared, what methods and classes should be abstract and what methods should have bodies, if anything should be an interface, and what should be private/protected/public. Make use of inheritance! (Pay attention to the language — if something applies to creatures, for example, don't repeat that element for each particular kind of creature.) Also make use of super and this as needed to reuse code instead of repeating things.

  • Creatures are things that have a position in the field and can move. Both animals and werebushes are creatures. Creatures have getters getRow and getColumn(), a setter setPosition which takes the row and column as parameters and sets the position accordingly, a getNextMove method which takes a Field object as a parameter and returns one of the constants defined in Direction, and a reset method which clears the creature's memory.

  • Werebushes are bushes which sometimes turn into animals. (Usually this is around the time of the full moon.) They have an instance variable for the animal they transform into and transformation interval and duration counters which determine when they transform and how long they stay transformed.

  • Werebushes have a constructor which takes the animal to transform into as a constructor and initializes that instance variable accordingly. The transformation interval and duration should be set to 20 and 5, respectively.

  • The position of a werebush is the position of its animal, even if it isn't currently transformed. The werebush's memory is its interval and duration counters plus whatever memory its animal has, so reset should set the counters back to 20 and 5, respectively, and reset the animal's memory. A werebush is drawn as its animal if it is transformed (the interval counter is 0) and as a bush otherwise. getNextMove should do the following: if the interval counter is greater than 0, decrement it and return Direction.NONE (no move when it is a bush), otherwise if the duration counter is greater than 0, decrement it and return the animal's next move (the werebush moves like its animal when transformed), and if both counters are 0, reset them to 20 and 5, respectively, and return Direction.NONE (the werebush is back to bush form).

When you are done, you should be able to run the main program (RabbitHunt). If all is well, there should be no error messages and the program should work just like the demo version.


Exercise #3: Simulation

The simulation contains and coordinates all of the things in the field. You've been provided with a class Sim which has the basics for a simulation: it stores the field and the step number, and provides step and draw for one step of the animation and drawing the scene, respectively.

  • Write a class RabbitHuntSim which extends Sim to provide functionality specific to this rabbit-fox-sloth simulation, as described below.

In addition to what is inherited from Sim, RabbitHuntSim should contain:

  • a boolean instance variable indicating whether or not the rabbit is free (i.e. it hasn't been caught by the fox)

  • an array of the creatures in the field (instance variable) — this is just one array for all of the creatures, not separate arrays for each kind of creature

  • a constructor which takes the dimensions of the field (the number of rows and the number of columns) as parameters, and which initializes the instance variables (details below)

  • a getter isRabbitFree which returns whether or not the rabbit is free

  • a getter isOver which overrides the version in Sim and returns whether or not the simulation is over (it is over if the rabbit is no longer free or there have been more than 100 steps)

  • methods reset and step which extend the versions in Sim (details below)

You may add additional private helper methods if you find that convenient. (A private helper method is a method which is used only internally within a class and so is private instead of public.)

If you haven't already looked at Field, you should do now (before you start writing RabbitHuntSim) — being familiar with what methods are available will make writing RabbitHuntSim much easier. Remember that you only need to look at public and protected things (constants, variables, methods) and the associated comments — while you can look at the method bodies if you are curious, they are not important for using the class.

Instance variable details: The array of creatures is being used as a holder of a collection. It is not a 2D array corresponding to the grid of the field.

Constructor details: As usual, the constructor should initialize the instance variables and you should use the superclass constructor to initialize the inherited instance variables. For the new instance variables: the rabbit is initially free, and the array of creatures should be initialized to contain one rabbit, one fox, 15 sloths, and at least three werebushes (at least one that transforms to a rabbit, at least one that transforms to a fox, and at least one that transforms to a sloth). The creatures should be placed randomly in the field, along with a reasonable number of randomly-placed bushes. Things should not be placed on top of each other.

reset details: This method should reset the simulation, which means extending Sim's reset method to also randomly place a new group of bushes, reset and randomly place the existing creatures, and restore the rabbit to freedom. ("Extending" means calling Sim's version of reset before doing the new tasks.) reset should not repaint the field.

step details: This method does most of the work involved in one step of the simulation: if the rabbit is free, Sim's step should be called and then, for each creature:

  • determine where the creature wants to move (store the direction in a variable) — for this, you will need to pass the field to getNextMove
  • if the creature is a fox and the move will move it to the same position as a rabbit, the fox moves to that position and the rabbit is caught (i.e. no longer free)
  • otherwise, if the creature can move in the desired direction, it is moved

step should not repaint the field, and you should make sure your code works no matter where in the array the fox and rabbit are stored — don't assume that the rabbit is always in position 0, for example. This means you'll need to use instanceof to determine which creature is the fox and which is the rabbit — see the description of instanceof in section 5.5.3 in the text or its usage in AccountDemo3.java from class.

When you are done, run the main program (RabbitHunt). If all is well, the "*** provided RabbitHuntSim! ***" message should have gone away, there are no error messages, and your program should work just like the demo version.