You will work with an existing project that does already use inheritance and subtyping but has scope for using it more extensively. This project is based on the foxes-and-rabbits projects described in Chapter 10 of the course text book. The project simulates three wolfs hunting a single sheep. The wolfs do not walk randomly but head for the sheep. The eld has boundaries at the top and bottom, but the left and right hand sides wrap around.
You start with the given project wolfSheepStart. Familiarise yourself with the source les of the project. These are based on foxes-and-rabbits-v2 but there are substantial dierences. For instance, the Wolf and Sheep classes are relatively simple with common methods having been moved into abstract class Animal. AnimalFactory is a new class. Currently it does little, but you will be adding further functionality to it. Make sure that you read through the Field class as it stores Animal objects on behalf of the simulation.
The assessment will be marked out of 100 and provisional marks have been associated with the individual components.
Make sure that you do not only write code, but that you also write or update appropriate comments for all classes and methods. Furthermore, you have to keep to the program style guide of the book. After marking out of 100 as indicated below, between 0% and 20% may be subtracted if you violate the style guide. In extreme cases even more than 20% can be subtracted.
Create a unit test class for the class Wolf.
Write three unit tests to test that after a call of the method moveToLocation(...) a Wolf has indeed the location that is was moved to.
Write three unit tests to test that after a call of the method act() a Wolf is either at its original location or an adjacent location (as dened in class Field).
You can use the classes Sheep, Field and Location, assuming that they work correctly.
Add a post-condition to express that after a call of the method moveToLocation(...) an Animal has indeed the location that is was moved to.
Add a post-condition to express that after a call of the method act() a Sheep is either at its original location or an adjacent location (as dened in class Field).
Record any post-condition in the relevant comment and add a corresponding assert statement.
Although this version of the project has already decoupled the simulateOneStep() method from Wolf and Sheep, the Simulator class remains directly coupled to Wolf and Sheep because of the way that these are created at the start of a simulation.
Move all of the responsibility for Wolf and Sheep creation to the AnimalFactory class. Ensure that the Simulator class no longer has any Wolf- or Sheep-specic knowledge but only deals with Animals. For that you have to modify the constructors of the Simulation class so that they take an AnimalFactory object as parameter.
Afterwards the simulation should work as before.
In the future we want to use the Simulator class with dierent animal factories. Hence rename the class AnimalFactory into AnimalFactorySimple and introduce a new interface named AnimalFactory. Make AnimalFactorySimple implement the interface AnimalFactory. Ensure that the Simulation constructors work with AnimalFactory interfaces. In the future we can use class Simulator for lots of dierent simulations without any changes.
Afterwards the simulation should work as before.
The sheep currently walks around randomly and thus is easily caught by a wolf. Implement a new class CleverSheep for a sheep that still walks mostly randomly, but, if possible, avoids any location that can be reached by any wolf in the next time step.
If we want to use CleverSheep in our simulation, we face the problem that Wolf objects use Sheep objects in their implementation. To solve this problem, we rename the old class Sheep into StupidSheep (also rename the test class for Sheep) and introduce an interface Sheep. We will have two implementations of this interface.
Now implement a new class AnimalFactoryBetter that is like AnimalFactorySimple, but creates a CleverSheep instead of a StupidSheep.
Check that the Simulation with AnimalFactoryBetter works ne.
Compared to the CleverSheep the wolfs now look pretty stupid. Rename class Wolf into class StupidWolf. Write a new class CleverWolf for wolfs that are better at hunting. The aim should be that two wolfs can always catch a CleverSheep. The only limitation is that in one step a wolf can only go to a neighbouring location, not any further. The two wolfs may explicitly cooperate. Hence you may actually want to dene a separate class for each of these two wolfs. Keep the hunting strategy and its implementation as simple as possible. Document the hunting strategy in the class comments.
Write a new class AnimalFactoryFinal that creates one CleverSheep and two CleverWolfs. Check the Simulation with it.