first commit
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
#BlueJ class context
|
||||
comment0.params=field\ location
|
||||
comment0.target=Animal(Field,\ Location)
|
||||
comment0.text=\n\ Create\ a\ new\ animal\ at\ location\ in\ field.\n\ \n\ @param\ field\ The\ field\ currently\ occupied.\n\ @param\ location\ The\ location\ within\ the\ field.\n
|
||||
comment1.params=newAnimals
|
||||
comment1.target=void\ act(java.util.List)
|
||||
comment1.text=\n\ Make\ this\ animal\ act\ -\ that\ is\:\ make\ it\ do\n\ whatever\ it\ wants/needs\ to\ do.\n\ @param\ newAnimals\ A\ list\ to\ receive\ newly\ born\ animals.\n
|
||||
comment2.params=
|
||||
comment2.target=boolean\ isAlive()
|
||||
comment2.text=\n\ Check\ whether\ the\ animal\ is\ alive\ or\ not.\n\ @return\ true\ if\ the\ animal\ is\ still\ alive.\n
|
||||
comment3.params=
|
||||
comment3.target=void\ setDead()
|
||||
comment3.text=\n\ Indicate\ that\ the\ animal\ is\ no\ longer\ alive.\n\ It\ is\ removed\ from\ the\ field.\n
|
||||
comment4.params=
|
||||
comment4.target=Location\ getLocation()
|
||||
comment4.text=\n\ Return\ the\ animal's\ location.\n\ @return\ The\ animal's\ location.\n
|
||||
comment5.params=newLocation
|
||||
comment5.target=void\ setLocation(Location)
|
||||
comment5.text=\n\ Place\ the\ animal\ at\ the\ new\ location\ in\ the\ given\ field.\n\ @param\ newLocation\ The\ animal's\ new\ location.\n
|
||||
comment6.params=
|
||||
comment6.target=Field\ getField()
|
||||
comment6.text=\n\ Return\ the\ animal's\ field.\n\ @return\ The\ animal's\ field.\n
|
||||
numComments=7
|
@@ -0,0 +1,91 @@
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class representing shared characteristics of animals.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29 (2)
|
||||
*/
|
||||
public abstract class Animal
|
||||
{
|
||||
// Whether the animal is alive or not.
|
||||
private boolean alive;
|
||||
// The animal's field.
|
||||
private Field field;
|
||||
// The animal's position in the field.
|
||||
private Location location;
|
||||
|
||||
/**
|
||||
* Create a new animal at location in field.
|
||||
*
|
||||
* @param field The field currently occupied.
|
||||
* @param location The location within the field.
|
||||
*/
|
||||
public Animal(Field field, Location location)
|
||||
{
|
||||
alive = true;
|
||||
this.field = field;
|
||||
setLocation(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this animal act - that is: make it do
|
||||
* whatever it wants/needs to do.
|
||||
* @param newAnimals A list to receive newly born animals.
|
||||
*/
|
||||
abstract public void act(List<Animal> newAnimals);
|
||||
|
||||
/**
|
||||
* Check whether the animal is alive or not.
|
||||
* @return true if the animal is still alive.
|
||||
*/
|
||||
protected boolean isAlive()
|
||||
{
|
||||
return alive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the animal is no longer alive.
|
||||
* It is removed from the field.
|
||||
*/
|
||||
protected void setDead()
|
||||
{
|
||||
alive = false;
|
||||
if(location != null) {
|
||||
field.clear(location);
|
||||
location = null;
|
||||
field = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the animal's location.
|
||||
* @return The animal's location.
|
||||
*/
|
||||
protected Location getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the animal at the new location in the given field.
|
||||
* @param newLocation The animal's new location.
|
||||
*/
|
||||
protected void setLocation(Location newLocation)
|
||||
{
|
||||
if(location != null) {
|
||||
field.clear(location);
|
||||
}
|
||||
location = newLocation;
|
||||
field.place(this, newLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the animal's field.
|
||||
* @return The animal's field.
|
||||
*/
|
||||
protected Field getField()
|
||||
{
|
||||
return field;
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
#BlueJ class context
|
||||
comment0.params=name
|
||||
comment0.target=Counter(java.lang.String)
|
||||
comment0.text=\n\ Provide\ a\ name\ for\ one\ of\ the\ simulation\ types.\n\ @param\ name\ \ A\ name,\ e.g.\ "Fox".\n
|
||||
comment1.params=
|
||||
comment1.target=java.lang.String\ getName()
|
||||
comment1.text=\n\ @return\ The\ short\ description\ of\ this\ type.\n
|
||||
comment2.params=
|
||||
comment2.target=int\ getCount()
|
||||
comment2.text=\n\ @return\ The\ current\ count\ for\ this\ type.\n
|
||||
comment3.params=
|
||||
comment3.target=void\ increment()
|
||||
comment3.text=\n\ Increment\ the\ current\ count\ by\ one.\n
|
||||
comment4.params=
|
||||
comment4.target=void\ reset()
|
||||
comment4.text=\n\ Reset\ the\ current\ count\ to\ zero.\n
|
||||
numComments=5
|
@@ -0,0 +1,60 @@
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Provide a counter for a participant in the simulation.
|
||||
* This includes an identifying string and a count of how
|
||||
* many participants of this type currently exist within
|
||||
* the simulation.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29
|
||||
*/
|
||||
public class Counter
|
||||
{
|
||||
// A name for this type of simulation participant
|
||||
private String name;
|
||||
// How many of this type exist in the simulation.
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* Provide a name for one of the simulation types.
|
||||
* @param name A name, e.g. "Fox".
|
||||
*/
|
||||
public Counter(String name)
|
||||
{
|
||||
this.name = name;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The short description of this type.
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current count for this type.
|
||||
*/
|
||||
public int getCount()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the current count by one.
|
||||
*/
|
||||
public void increment()
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current count to zero.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
#BlueJ class context
|
||||
comment0.params=depth\ width
|
||||
comment0.target=Field(int,\ int)
|
||||
comment0.text=\n\ Represent\ a\ field\ of\ the\ given\ dimensions.\n\ @param\ depth\ The\ depth\ of\ the\ field.\n\ @param\ width\ The\ width\ of\ the\ field.\n
|
||||
comment1.params=
|
||||
comment1.target=void\ clear()
|
||||
comment1.text=\n\ Empty\ the\ field.\n
|
||||
comment10.params=location
|
||||
comment10.target=java.util.List\ adjacentLocations(Location)
|
||||
comment10.text=\n\ Return\ a\ shuffled\ list\ of\ locations\ adjacent\ to\ the\ given\ one.\n\ The\ list\ will\ not\ include\ the\ location\ itself.\n\ All\ locations\ will\ lie\ within\ the\ grid.\n\ @param\ location\ The\ location\ from\ which\ to\ generate\ adjacencies.\n\ @return\ A\ list\ of\ locations\ adjacent\ to\ that\ given.\n
|
||||
comment11.params=
|
||||
comment11.target=int\ getDepth()
|
||||
comment11.text=\n\ Return\ the\ depth\ of\ the\ field.\n\ @return\ The\ depth\ of\ the\ field.\n
|
||||
comment12.params=
|
||||
comment12.target=int\ getWidth()
|
||||
comment12.text=\n\ Return\ the\ width\ of\ the\ field.\n\ @return\ The\ width\ of\ the\ field.\n
|
||||
comment2.params=location
|
||||
comment2.target=void\ clear(Location)
|
||||
comment2.text=\n\ Clear\ the\ given\ location.\n\ @param\ location\ The\ location\ to\ clear.\n
|
||||
comment3.params=animal\ row\ col
|
||||
comment3.target=void\ place(java.lang.Object,\ int,\ int)
|
||||
comment3.text=\n\ Place\ an\ animal\ at\ the\ given\ location.\n\ If\ there\ is\ already\ an\ animal\ at\ the\ location\ it\ will\n\ be\ lost.\n\ @param\ animal\ The\ animal\ to\ be\ placed.\n\ @param\ row\ Row\ coordinate\ of\ the\ location.\n\ @param\ col\ Column\ coordinate\ of\ the\ location.\n
|
||||
comment4.params=animal\ location
|
||||
comment4.target=void\ place(java.lang.Object,\ Location)
|
||||
comment4.text=\n\ Place\ an\ animal\ at\ the\ given\ location.\n\ If\ there\ is\ already\ an\ animal\ at\ the\ location\ it\ will\n\ be\ lost.\n\ @param\ animal\ The\ animal\ to\ be\ placed.\n\ @param\ location\ Where\ to\ place\ the\ animal.\n
|
||||
comment5.params=location
|
||||
comment5.target=java.lang.Object\ getObjectAt(Location)
|
||||
comment5.text=\n\ Return\ the\ animal\ at\ the\ given\ location,\ if\ any.\n\ @param\ location\ Where\ in\ the\ field.\n\ @return\ The\ animal\ at\ the\ given\ location,\ or\ null\ if\ there\ is\ none.\n
|
||||
comment6.params=row\ col
|
||||
comment6.target=java.lang.Object\ getObjectAt(int,\ int)
|
||||
comment6.text=\n\ Return\ the\ animal\ at\ the\ given\ location,\ if\ any.\n\ @param\ row\ The\ desired\ row.\n\ @param\ col\ The\ desired\ column.\n\ @return\ The\ animal\ at\ the\ given\ location,\ or\ null\ if\ there\ is\ none.\n
|
||||
comment7.params=location
|
||||
comment7.target=Location\ randomAdjacentLocation(Location)
|
||||
comment7.text=\n\ Generate\ a\ random\ location\ that\ is\ adjacent\ to\ the\n\ given\ location,\ or\ is\ the\ same\ location.\n\ The\ returned\ location\ will\ be\ within\ the\ valid\ bounds\n\ of\ the\ field.\n\ @param\ location\ The\ location\ from\ which\ to\ generate\ an\ adjacency.\n\ @return\ A\ valid\ location\ within\ the\ grid\ area.\n
|
||||
comment8.params=location
|
||||
comment8.target=java.util.List\ getFreeAdjacentLocations(Location)
|
||||
comment8.text=\n\ Get\ a\ shuffled\ list\ of\ the\ free\ adjacent\ locations.\n\ @param\ location\ Get\ locations\ adjacent\ to\ this.\n\ @return\ A\ list\ of\ free\ adjacent\ locations.\n
|
||||
comment9.params=location
|
||||
comment9.target=Location\ freeAdjacentLocation(Location)
|
||||
comment9.text=\n\ Try\ to\ find\ a\ free\ location\ that\ is\ adjacent\ to\ the\n\ given\ location.\ If\ there\ is\ none,\ return\ null.\n\ The\ returned\ location\ will\ be\ within\ the\ valid\ bounds\n\ of\ the\ field.\n\ @param\ location\ The\ location\ from\ which\ to\ generate\ an\ adjacency.\n\ @return\ A\ valid\ location\ within\ the\ grid\ area.\n
|
||||
numComments=13
|
@@ -0,0 +1,206 @@
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Represent a rectangular grid of field positions.
|
||||
* Each position is able to store a single animal.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29
|
||||
*/
|
||||
public class Field
|
||||
{
|
||||
// A random number generator for providing random locations.
|
||||
private static final Random rand = Randomizer.getRandom();
|
||||
|
||||
// The depth and width of the field.
|
||||
private int depth, width;
|
||||
// Storage for the animals.
|
||||
private Object[][] field;
|
||||
|
||||
/**
|
||||
* Represent a field of the given dimensions.
|
||||
* @param depth The depth of the field.
|
||||
* @param width The width of the field.
|
||||
*/
|
||||
public Field(int depth, int width)
|
||||
{
|
||||
this.depth = depth;
|
||||
this.width = width;
|
||||
field = new Object[depth][width];
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty the field.
|
||||
*/
|
||||
public void clear()
|
||||
{
|
||||
for(int row = 0; row < depth; row++) {
|
||||
for(int col = 0; col < width; col++) {
|
||||
field[row][col] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the given location.
|
||||
* @param location The location to clear.
|
||||
*/
|
||||
public void clear(Location location)
|
||||
{
|
||||
field[location.getRow()][location.getCol()] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Place an animal at the given location.
|
||||
* If there is already an animal at the location it will
|
||||
* be lost.
|
||||
* @param animal The animal to be placed.
|
||||
* @param row Row coordinate of the location.
|
||||
* @param col Column coordinate of the location.
|
||||
*/
|
||||
public void place(Object animal, int row, int col)
|
||||
{
|
||||
place(animal, new Location(row, col));
|
||||
}
|
||||
|
||||
/**
|
||||
* Place an animal at the given location.
|
||||
* If there is already an animal at the location it will
|
||||
* be lost.
|
||||
* @param animal The animal to be placed.
|
||||
* @param location Where to place the animal.
|
||||
*/
|
||||
public void place(Object animal, Location location)
|
||||
{
|
||||
field[location.getRow()][location.getCol()] = animal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the animal at the given location, if any.
|
||||
* @param location Where in the field.
|
||||
* @return The animal at the given location, or null if there is none.
|
||||
*/
|
||||
public Object getObjectAt(Location location)
|
||||
{
|
||||
return getObjectAt(location.getRow(), location.getCol());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the animal at the given location, if any.
|
||||
* @param row The desired row.
|
||||
* @param col The desired column.
|
||||
* @return The animal at the given location, or null if there is none.
|
||||
*/
|
||||
public Object getObjectAt(int row, int col)
|
||||
{
|
||||
return field[row][col];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random location that is adjacent to the
|
||||
* given location, or is the same location.
|
||||
* The returned location will be within the valid bounds
|
||||
* of the field.
|
||||
* @param location The location from which to generate an adjacency.
|
||||
* @return A valid location within the grid area.
|
||||
*/
|
||||
public Location randomAdjacentLocation(Location location)
|
||||
{
|
||||
List<Location> adjacent = adjacentLocations(location);
|
||||
return adjacent.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a shuffled list of the free adjacent locations.
|
||||
* @param location Get locations adjacent to this.
|
||||
* @return A list of free adjacent locations.
|
||||
*/
|
||||
public List<Location> getFreeAdjacentLocations(Location location)
|
||||
{
|
||||
List<Location> free = new LinkedList<>();
|
||||
List<Location> adjacent = adjacentLocations(location);
|
||||
for(Location next : adjacent) {
|
||||
if(getObjectAt(next) == null) {
|
||||
free.add(next);
|
||||
}
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a free location that is adjacent to the
|
||||
* given location. If there is none, return null.
|
||||
* The returned location will be within the valid bounds
|
||||
* of the field.
|
||||
* @param location The location from which to generate an adjacency.
|
||||
* @return A valid location within the grid area.
|
||||
*/
|
||||
public Location freeAdjacentLocation(Location location)
|
||||
{
|
||||
// The available free ones.
|
||||
List<Location> free = getFreeAdjacentLocations(location);
|
||||
if(free.size() > 0) {
|
||||
return free.get(0);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a shuffled list of locations adjacent to the given one.
|
||||
* The list will not include the location itself.
|
||||
* All locations will lie within the grid.
|
||||
* @param location The location from which to generate adjacencies.
|
||||
* @return A list of locations adjacent to that given.
|
||||
*/
|
||||
public List<Location> adjacentLocations(Location location)
|
||||
{
|
||||
assert location != null : "Null location passed to adjacentLocations";
|
||||
// The list of locations to be returned.
|
||||
List<Location> locations = new LinkedList<>();
|
||||
if(location != null) {
|
||||
int row = location.getRow();
|
||||
int col = location.getCol();
|
||||
for(int roffset = -1; roffset <= 1; roffset++) {
|
||||
int nextRow = row + roffset;
|
||||
if(nextRow >= 0 && nextRow < depth) {
|
||||
for(int coffset = -1; coffset <= 1; coffset++) {
|
||||
int nextCol = col + coffset;
|
||||
// Exclude invalid locations and the original location.
|
||||
if(nextCol >= 0 && nextCol < width && (roffset != 0 || coffset != 0)) {
|
||||
locations.add(new Location(nextRow, nextCol));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle the list. Several other methods rely on the list
|
||||
// being in a random order.
|
||||
Collections.shuffle(locations, rand);
|
||||
}
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the depth of the field.
|
||||
* @return The depth of the field.
|
||||
*/
|
||||
public int getDepth()
|
||||
{
|
||||
return depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the width of the field.
|
||||
* @return The width of the field.
|
||||
*/
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
#BlueJ class context
|
||||
comment0.params=
|
||||
comment0.target=FieldStats()
|
||||
comment0.text=\n\ Construct\ a\ FieldStats\ object.\n
|
||||
comment1.params=field
|
||||
comment1.target=java.lang.String\ getPopulationDetails(Field)
|
||||
comment1.text=\n\ Get\ details\ of\ what\ is\ in\ the\ field.\n\ @return\ A\ string\ describing\ what\ is\ in\ the\ field.\n
|
||||
comment2.params=
|
||||
comment2.target=void\ reset()
|
||||
comment2.text=\n\ Invalidate\ the\ current\ set\ of\ statistics;\ reset\ all\ \n\ counts\ to\ zero.\n
|
||||
comment3.params=animalClass
|
||||
comment3.target=void\ incrementCount(java.lang.Class)
|
||||
comment3.text=\n\ Increment\ the\ count\ for\ one\ class\ of\ animal.\n\ @param\ animalClass\ The\ class\ of\ animal\ to\ increment.\n
|
||||
comment4.params=
|
||||
comment4.target=void\ countFinished()
|
||||
comment4.text=\n\ Indicate\ that\ an\ animal\ count\ has\ been\ completed.\n
|
||||
comment5.params=field
|
||||
comment5.target=boolean\ isViable(Field)
|
||||
comment5.text=\n\ Determine\ whether\ the\ simulation\ is\ still\ viable.\n\ I.e.,\ should\ it\ continue\ to\ run.\n\ @return\ true\ If\ there\ is\ more\ than\ one\ species\ alive.\n
|
||||
comment6.params=field
|
||||
comment6.target=void\ generateCounts(Field)
|
||||
comment6.text=\n\ Generate\ counts\ of\ the\ number\ of\ foxes\ and\ rabbits.\n\ These\ are\ not\ kept\ up\ to\ date\ as\ foxes\ and\ rabbits\n\ are\ placed\ in\ the\ field,\ but\ only\ when\ a\ request\n\ is\ made\ for\ the\ information.\n\ @param\ field\ The\ field\ to\ generate\ the\ stats\ for.\n
|
||||
numComments=7
|
@@ -0,0 +1,128 @@
|
||||
import java.awt.Color;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* This class collects and provides some statistical data on the state
|
||||
* of a field. It is flexible: it will create and maintain a counter
|
||||
* for any class of object that is found within the field.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29
|
||||
*/
|
||||
public class FieldStats
|
||||
{
|
||||
// Counters for each type of entity (fox, rabbit, etc.) in the simulation.
|
||||
private HashMap<Class, Counter> counters;
|
||||
// Whether the counters are currently up to date.
|
||||
private boolean countsValid;
|
||||
|
||||
/**
|
||||
* Construct a FieldStats object.
|
||||
*/
|
||||
public FieldStats()
|
||||
{
|
||||
// Set up a collection for counters for each type of animal that
|
||||
// we might find
|
||||
counters = new HashMap<>();
|
||||
countsValid = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of what is in the field.
|
||||
* @return A string describing what is in the field.
|
||||
*/
|
||||
public String getPopulationDetails(Field field)
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
if(!countsValid) {
|
||||
generateCounts(field);
|
||||
}
|
||||
for(Class key : counters.keySet()) {
|
||||
Counter info = counters.get(key);
|
||||
buffer.append(info.getName());
|
||||
buffer.append(": ");
|
||||
buffer.append(info.getCount());
|
||||
buffer.append(' ');
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the current set of statistics; reset all
|
||||
* counts to zero.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
countsValid = false;
|
||||
for(Class key : counters.keySet()) {
|
||||
Counter count = counters.get(key);
|
||||
count.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the count for one class of animal.
|
||||
* @param animalClass The class of animal to increment.
|
||||
*/
|
||||
public void incrementCount(Class animalClass)
|
||||
{
|
||||
Counter count = counters.get(animalClass);
|
||||
if(count == null) {
|
||||
// We do not have a counter for this species yet.
|
||||
// Create one.
|
||||
count = new Counter(animalClass.getName());
|
||||
counters.put(animalClass, count);
|
||||
}
|
||||
count.increment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that an animal count has been completed.
|
||||
*/
|
||||
public void countFinished()
|
||||
{
|
||||
countsValid = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the simulation is still viable.
|
||||
* I.e., should it continue to run.
|
||||
* @return true If there is more than one species alive.
|
||||
*/
|
||||
public boolean isViable(Field field)
|
||||
{
|
||||
// How many counts are non-zero.
|
||||
int nonZero = 0;
|
||||
if(!countsValid) {
|
||||
generateCounts(field);
|
||||
}
|
||||
for(Class key : counters.keySet()) {
|
||||
Counter info = counters.get(key);
|
||||
if(info.getCount() > 0) {
|
||||
nonZero++;
|
||||
}
|
||||
}
|
||||
return nonZero > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate counts of the number of foxes and rabbits.
|
||||
* These are not kept up to date as foxes and rabbits
|
||||
* are placed in the field, but only when a request
|
||||
* is made for the information.
|
||||
* @param field The field to generate the stats for.
|
||||
*/
|
||||
private void generateCounts(Field field)
|
||||
{
|
||||
reset();
|
||||
for(int row = 0; row < field.getDepth(); row++) {
|
||||
for(int col = 0; col < field.getWidth(); col++) {
|
||||
Object animal = field.getObjectAt(row, col);
|
||||
if(animal != null) {
|
||||
incrementCount(animal.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
countsValid = true;
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
#BlueJ class context
|
||||
comment0.params=randomAge\ field\ location
|
||||
comment0.target=Fox(boolean,\ Field,\ Location)
|
||||
comment0.text=\n\ Create\ a\ fox.\ A\ fox\ can\ be\ created\ as\ a\ new\ born\ (age\ zero\n\ and\ not\ hungry)\ or\ with\ a\ random\ age\ and\ food\ level.\n\ \n\ @param\ randomAge\ If\ true,\ the\ fox\ will\ have\ random\ age\ and\ hunger\ level.\n\ @param\ field\ The\ field\ currently\ occupied.\n\ @param\ location\ The\ location\ within\ the\ field.\n
|
||||
comment1.params=newFoxes
|
||||
comment1.target=void\ act(java.util.List)
|
||||
comment1.text=\n\ This\ is\ what\ the\ fox\ does\ most\ of\ the\ time\:\ it\ hunts\ for\n\ rabbits.\ In\ the\ process,\ it\ might\ breed,\ die\ of\ hunger,\n\ or\ die\ of\ old\ age.\n\ @param\ field\ The\ field\ currently\ occupied.\n\ @param\ newFoxes\ A\ list\ to\ return\ newly\ born\ foxes.\n
|
||||
comment2.params=
|
||||
comment2.target=void\ incrementAge()
|
||||
comment2.text=\n\ Increase\ the\ age.\ This\ could\ result\ in\ the\ fox's\ death.\n
|
||||
comment3.params=
|
||||
comment3.target=void\ incrementHunger()
|
||||
comment3.text=\n\ Make\ this\ fox\ more\ hungry.\ This\ could\ result\ in\ the\ fox's\ death.\n
|
||||
comment4.params=
|
||||
comment4.target=Location\ findFood()
|
||||
comment4.text=\n\ Look\ for\ rabbits\ adjacent\ to\ the\ current\ location.\n\ Only\ the\ first\ live\ rabbit\ is\ eaten.\n\ @return\ Where\ food\ was\ found,\ or\ null\ if\ it\ wasn't.\n
|
||||
comment5.params=newFoxes
|
||||
comment5.target=void\ giveBirth(java.util.List)
|
||||
comment5.text=\n\ Check\ whether\ or\ not\ this\ fox\ is\ to\ give\ birth\ at\ this\ step.\n\ New\ births\ will\ be\ made\ into\ free\ adjacent\ locations.\n\ @param\ newFoxes\ A\ list\ to\ return\ newly\ born\ foxes.\n
|
||||
comment6.params=
|
||||
comment6.target=int\ breed()
|
||||
comment6.text=\n\ Generate\ a\ number\ representing\ the\ number\ of\ births,\n\ if\ it\ can\ breed.\n\ @return\ The\ number\ of\ births\ (may\ be\ zero).\n
|
||||
comment7.params=
|
||||
comment7.target=boolean\ canBreed()
|
||||
comment7.text=\n\ A\ fox\ can\ breed\ if\ it\ has\ reached\ the\ breeding\ age.\n
|
||||
numComments=8
|
@@ -0,0 +1,174 @@
|
||||
import java.util.List;
|
||||
import java.util.Iterator;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* A simple model of a fox.
|
||||
* Foxes age, move, eat rabbits, and die.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29 (2)
|
||||
*/
|
||||
public class Fox extends Animal
|
||||
{
|
||||
// Characteristics shared by all foxes (class variables).
|
||||
|
||||
// The age at which a fox can start to breed.
|
||||
private static final int BREEDING_AGE = 15;
|
||||
// The age to which a fox can live.
|
||||
private static final int MAX_AGE = 150;
|
||||
// The likelihood of a fox breeding.
|
||||
private static final double BREEDING_PROBABILITY = 0.08;
|
||||
// The maximum number of births.
|
||||
private static final int MAX_LITTER_SIZE = 2;
|
||||
// The food value of a single rabbit. In effect, this is the
|
||||
// number of steps a fox can go before it has to eat again.
|
||||
private static final int RABBIT_FOOD_VALUE = 9;
|
||||
// A shared random number generator to control breeding.
|
||||
private static final Random rand = Randomizer.getRandom();
|
||||
|
||||
// Individual characteristics (instance fields).
|
||||
// The fox's age.
|
||||
private int age;
|
||||
// The fox's food level, which is increased by eating rabbits.
|
||||
private int foodLevel;
|
||||
|
||||
/**
|
||||
* Create a fox. A fox can be created as a new born (age zero
|
||||
* and not hungry) or with a random age and food level.
|
||||
*
|
||||
* @param randomAge If true, the fox will have random age and hunger level.
|
||||
* @param field The field currently occupied.
|
||||
* @param location The location within the field.
|
||||
*/
|
||||
public Fox(boolean randomAge, Field field, Location location)
|
||||
{
|
||||
super(field, location);
|
||||
if(randomAge) {
|
||||
age = rand.nextInt(MAX_AGE);
|
||||
foodLevel = rand.nextInt(RABBIT_FOOD_VALUE);
|
||||
}
|
||||
else {
|
||||
age = 0;
|
||||
foodLevel = RABBIT_FOOD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is what the fox does most of the time: it hunts for
|
||||
* rabbits. In the process, it might breed, die of hunger,
|
||||
* or die of old age.
|
||||
* @param field The field currently occupied.
|
||||
* @param newFoxes A list to return newly born foxes.
|
||||
*/
|
||||
public void act(List<Animal> newFoxes)
|
||||
{
|
||||
incrementAge();
|
||||
incrementHunger();
|
||||
if(isAlive()) {
|
||||
giveBirth(newFoxes);
|
||||
// Move towards a source of food if found.
|
||||
Location newLocation = findFood();
|
||||
if(newLocation == null) {
|
||||
// No food found - try to move to a free location.
|
||||
newLocation = getField().freeAdjacentLocation(getLocation());
|
||||
}
|
||||
// See if it was possible to move.
|
||||
if(newLocation != null) {
|
||||
setLocation(newLocation);
|
||||
}
|
||||
else {
|
||||
// Overcrowding.
|
||||
setDead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the age. This could result in the fox's death.
|
||||
*/
|
||||
private void incrementAge()
|
||||
{
|
||||
age++;
|
||||
if(age > MAX_AGE) {
|
||||
setDead();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this fox more hungry. This could result in the fox's death.
|
||||
*/
|
||||
private void incrementHunger()
|
||||
{
|
||||
foodLevel--;
|
||||
if(foodLevel <= 0) {
|
||||
setDead();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for rabbits adjacent to the current location.
|
||||
* Only the first live rabbit is eaten.
|
||||
* @return Where food was found, or null if it wasn't.
|
||||
*/
|
||||
private Location findFood()
|
||||
{
|
||||
Field field = getField();
|
||||
List<Location> adjacent = field.adjacentLocations(getLocation());
|
||||
Iterator<Location> it = adjacent.iterator();
|
||||
while(it.hasNext()) {
|
||||
Location where = it.next();
|
||||
Object animal = field.getObjectAt(where);
|
||||
if(animal instanceof Rabbit) {
|
||||
Rabbit rabbit = (Rabbit) animal;
|
||||
if(rabbit.isAlive()) {
|
||||
rabbit.setDead();
|
||||
foodLevel = RABBIT_FOOD_VALUE;
|
||||
return where;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not this fox is to give birth at this step.
|
||||
* New births will be made into free adjacent locations.
|
||||
* @param newFoxes A list to return newly born foxes.
|
||||
*/
|
||||
private void giveBirth(List<Animal> newFoxes)
|
||||
{
|
||||
// New foxes are born into adjacent locations.
|
||||
// Get a list of adjacent free locations.
|
||||
Field field = getField();
|
||||
List<Location> free = field.getFreeAdjacentLocations(getLocation());
|
||||
int births = breed();
|
||||
for(int b = 0; b < births && free.size() > 0; b++) {
|
||||
Location loc = free.remove(0);
|
||||
Fox young = new Fox(false, field, loc);
|
||||
newFoxes.add(young);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a number representing the number of births,
|
||||
* if it can breed.
|
||||
* @return The number of births (may be zero).
|
||||
*/
|
||||
private int breed()
|
||||
{
|
||||
int births = 0;
|
||||
if(canBreed() && rand.nextDouble() <= BREEDING_PROBABILITY) {
|
||||
births = rand.nextInt(MAX_LITTER_SIZE) + 1;
|
||||
}
|
||||
return births;
|
||||
}
|
||||
|
||||
/**
|
||||
* A fox can breed if it has reached the breeding age.
|
||||
*/
|
||||
private boolean canBreed()
|
||||
{
|
||||
return age >= BREEDING_AGE;
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
#BlueJ class context
|
||||
comment0.params=row\ col
|
||||
comment0.target=Location(int,\ int)
|
||||
comment0.text=\n\ Represent\ a\ row\ and\ column.\n\ @param\ row\ The\ row.\n\ @param\ col\ The\ column.\n
|
||||
comment1.params=obj
|
||||
comment1.target=boolean\ equals(java.lang.Object)
|
||||
comment1.text=\n\ Implement\ content\ equality.\n
|
||||
comment2.params=
|
||||
comment2.target=java.lang.String\ toString()
|
||||
comment2.text=\n\ Return\ a\ string\ of\ the\ form\ row,column\n\ @return\ A\ string\ representation\ of\ the\ location.\n
|
||||
comment3.params=
|
||||
comment3.target=int\ hashCode()
|
||||
comment3.text=\n\ Use\ the\ top\ 16\ bits\ for\ the\ row\ value\ and\ the\ bottom\ for\n\ the\ column.\ Except\ for\ very\ big\ grids,\ this\ should\ give\ a\n\ unique\ hash\ code\ for\ each\ (row,\ col)\ pair.\n\ @return\ A\ hashcode\ for\ the\ location.\n
|
||||
comment4.params=
|
||||
comment4.target=int\ getRow()
|
||||
comment4.text=\n\ @return\ The\ row.\n
|
||||
comment5.params=
|
||||
comment5.target=int\ getCol()
|
||||
comment5.text=\n\ @return\ The\ column.\n
|
||||
numComments=6
|
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Represent a location in a rectangular grid.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29
|
||||
*/
|
||||
public class Location
|
||||
{
|
||||
// Row and column positions.
|
||||
private int row;
|
||||
private int col;
|
||||
|
||||
/**
|
||||
* Represent a row and column.
|
||||
* @param row The row.
|
||||
* @param col The column.
|
||||
*/
|
||||
public Location(int row, int col)
|
||||
{
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement content equality.
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof Location) {
|
||||
Location other = (Location) obj;
|
||||
return row == other.getRow() && col == other.getCol();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string of the form row,column
|
||||
* @return A string representation of the location.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return row + "," + col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the top 16 bits for the row value and the bottom for
|
||||
* the column. Except for very big grids, this should give a
|
||||
* unique hash code for each (row, col) pair.
|
||||
* @return A hashcode for the location.
|
||||
*/
|
||||
public int hashCode()
|
||||
{
|
||||
return (row << 16) + col;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The row.
|
||||
*/
|
||||
public int getRow()
|
||||
{
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The column.
|
||||
*/
|
||||
public int getCol()
|
||||
{
|
||||
return col;
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
Project: foxes-and-rabbits-v2
|
||||
Authors: Michael Kölling and David J. Barnes
|
||||
|
||||
This project is part of the material for chapter 10 of the book
|
||||
|
||||
Objects First with Java - A Practical Introduction using BlueJ
|
||||
Sixth edition
|
||||
David J. Barnes and Michael Kölling
|
||||
Pearson Education, 2016
|
||||
|
||||
A predator-prey simulation involving foxes and rabbits in
|
||||
an enclosed rectangular field.
|
||||
|
||||
This is the first version of the simulation. This version
|
||||
does not use inheritance.
|
||||
|
||||
How to start:
|
||||
Create a Simulator object.
|
||||
Then call one of:
|
||||
+ simulateOneStep - for a single step.
|
||||
+ simulate - and supply a number (say 10) for that many steps.
|
||||
+ runLongSimulation - for a simulation of 500 steps.
|
@@ -0,0 +1,20 @@
|
||||
#BlueJ class context
|
||||
comment0.params=randomAge\ field\ location
|
||||
comment0.target=Rabbit(boolean,\ Field,\ Location)
|
||||
comment0.text=\n\ Create\ a\ new\ rabbit.\ A\ rabbit\ may\ be\ created\ with\ age\n\ zero\ (a\ new\ born)\ or\ with\ a\ random\ age.\n\ \n\ @param\ randomAge\ If\ true,\ the\ rabbit\ will\ have\ a\ random\ age.\n\ @param\ field\ The\ field\ currently\ occupied.\n\ @param\ location\ The\ location\ within\ the\ field.\n
|
||||
comment1.params=newRabbits
|
||||
comment1.target=void\ act(java.util.List)
|
||||
comment1.text=\n\ This\ is\ what\ the\ rabbit\ does\ most\ of\ the\ time\ -\ it\ runs\ \n\ around.\ Sometimes\ it\ will\ breed\ or\ die\ of\ old\ age.\n\ @param\ newRabbits\ A\ list\ to\ return\ newly\ born\ rabbits.\n
|
||||
comment2.params=
|
||||
comment2.target=void\ incrementAge()
|
||||
comment2.text=\n\ Increase\ the\ age.\n\ This\ could\ result\ in\ the\ rabbit's\ death.\n
|
||||
comment3.params=newRabbits
|
||||
comment3.target=void\ giveBirth(java.util.List)
|
||||
comment3.text=\n\ Check\ whether\ or\ not\ this\ rabbit\ is\ to\ give\ birth\ at\ this\ step.\n\ New\ births\ will\ be\ made\ into\ free\ adjacent\ locations.\n\ @param\ newRabbits\ A\ list\ to\ return\ newly\ born\ rabbits.\n
|
||||
comment4.params=
|
||||
comment4.target=int\ breed()
|
||||
comment4.text=\n\ Generate\ a\ number\ representing\ the\ number\ of\ births,\n\ if\ it\ can\ breed.\n\ @return\ The\ number\ of\ births\ (may\ be\ zero).\n
|
||||
comment5.params=
|
||||
comment5.target=boolean\ canBreed()
|
||||
comment5.text=\n\ A\ rabbit\ can\ breed\ if\ it\ has\ reached\ the\ breeding\ age.\n\ @return\ true\ if\ the\ rabbit\ can\ breed,\ false\ otherwise.\n
|
||||
numComments=6
|
@@ -0,0 +1,123 @@
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* A simple model of a rabbit.
|
||||
* Rabbits age, move, breed, and die.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29 (2)
|
||||
*/
|
||||
public class Rabbit extends Animal
|
||||
{
|
||||
// Characteristics shared by all rabbits (class variables).
|
||||
|
||||
// The age at which a rabbit can start to breed.
|
||||
private static final int BREEDING_AGE = 5;
|
||||
// The age to which a rabbit can live.
|
||||
private static final int MAX_AGE = 40;
|
||||
// The likelihood of a rabbit breeding.
|
||||
private static final double BREEDING_PROBABILITY = 0.12;
|
||||
// The maximum number of births.
|
||||
private static final int MAX_LITTER_SIZE = 4;
|
||||
// A shared random number generator to control breeding.
|
||||
private static final Random rand = Randomizer.getRandom();
|
||||
|
||||
// Individual characteristics (instance fields).
|
||||
|
||||
// The rabbit's age.
|
||||
private int age;
|
||||
|
||||
/**
|
||||
* Create a new rabbit. A rabbit may be created with age
|
||||
* zero (a new born) or with a random age.
|
||||
*
|
||||
* @param randomAge If true, the rabbit will have a random age.
|
||||
* @param field The field currently occupied.
|
||||
* @param location The location within the field.
|
||||
*/
|
||||
public Rabbit(boolean randomAge, Field field, Location location)
|
||||
{
|
||||
super(field, location);
|
||||
age = 0;
|
||||
if(randomAge) {
|
||||
age = rand.nextInt(MAX_AGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is what the rabbit does most of the time - it runs
|
||||
* around. Sometimes it will breed or die of old age.
|
||||
* @param newRabbits A list to return newly born rabbits.
|
||||
*/
|
||||
public void act(List<Animal> newRabbits)
|
||||
{
|
||||
incrementAge();
|
||||
if(isAlive()) {
|
||||
giveBirth(newRabbits);
|
||||
// Try to move into a free location.
|
||||
Location newLocation = getField().freeAdjacentLocation(getLocation());
|
||||
if(newLocation != null) {
|
||||
setLocation(newLocation);
|
||||
}
|
||||
else {
|
||||
// Overcrowding.
|
||||
setDead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the age.
|
||||
* This could result in the rabbit's death.
|
||||
*/
|
||||
private void incrementAge()
|
||||
{
|
||||
age++;
|
||||
if(age > MAX_AGE) {
|
||||
setDead();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether or not this rabbit is to give birth at this step.
|
||||
* New births will be made into free adjacent locations.
|
||||
* @param newRabbits A list to return newly born rabbits.
|
||||
*/
|
||||
private void giveBirth(List<Animal> newRabbits)
|
||||
{
|
||||
// New rabbits are born into adjacent locations.
|
||||
// Get a list of adjacent free locations.
|
||||
Field field = getField();
|
||||
List<Location> free = field.getFreeAdjacentLocations(getLocation());
|
||||
int births = breed();
|
||||
for(int b = 0; b < births && free.size() > 0; b++) {
|
||||
Location loc = free.remove(0);
|
||||
Rabbit young = new Rabbit(false, field, loc);
|
||||
newRabbits.add(young);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a number representing the number of births,
|
||||
* if it can breed.
|
||||
* @return The number of births (may be zero).
|
||||
*/
|
||||
private int breed()
|
||||
{
|
||||
int births = 0;
|
||||
if(canBreed() && rand.nextDouble() <= BREEDING_PROBABILITY) {
|
||||
births = rand.nextInt(MAX_LITTER_SIZE) + 1;
|
||||
}
|
||||
return births;
|
||||
}
|
||||
|
||||
/**
|
||||
* A rabbit can breed if it has reached the breeding age.
|
||||
* @return true if the rabbit can breed, false otherwise.
|
||||
*/
|
||||
private boolean canBreed()
|
||||
{
|
||||
return age >= BREEDING_AGE;
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
#BlueJ class context
|
||||
comment0.params=
|
||||
comment0.target=Randomizer()
|
||||
comment0.text=\n\ Constructor\ for\ objects\ of\ class\ Randomizer\n
|
||||
comment1.params=
|
||||
comment1.target=java.util.Random\ getRandom()
|
||||
comment1.text=\n\ Provide\ a\ random\ generator.\n\ @return\ A\ random\ object.\n
|
||||
comment2.params=
|
||||
comment2.target=void\ reset()
|
||||
comment2.text=\n\ Reset\ the\ randomization.\n\ This\ will\ have\ no\ effect\ if\ randomization\ is\ not\ through\n\ a\ shared\ Random\ generator.\n
|
||||
numComments=3
|
@@ -0,0 +1,52 @@
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Provide control over the randomization of the simulation. By using the shared, fixed-seed
|
||||
* randomizer, repeated runs will perform exactly the same (which helps with testing). Set
|
||||
* 'useShared' to false to get different random behaviour every time.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29
|
||||
*/
|
||||
public class Randomizer
|
||||
{
|
||||
// The default seed for control of randomization.
|
||||
private static final int SEED = 1111;
|
||||
// A shared Random object, if required.
|
||||
private static final Random rand = new Random(SEED);
|
||||
// Determine whether a shared random generator is to be provided.
|
||||
private static final boolean useShared = true;
|
||||
|
||||
/**
|
||||
* Constructor for objects of class Randomizer
|
||||
*/
|
||||
public Randomizer()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a random generator.
|
||||
* @return A random object.
|
||||
*/
|
||||
public static Random getRandom()
|
||||
{
|
||||
if(useShared) {
|
||||
return rand;
|
||||
}
|
||||
else {
|
||||
return new Random();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the randomization.
|
||||
* This will have no effect if randomization is not through
|
||||
* a shared Random generator.
|
||||
*/
|
||||
public static void reset()
|
||||
{
|
||||
if(useShared) {
|
||||
rand.setSeed(SEED);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
#BlueJ class context
|
||||
comment0.params=
|
||||
comment0.target=Simulator()
|
||||
comment0.text=\n\ Construct\ a\ simulation\ field\ with\ default\ size.\n
|
||||
comment1.params=depth\ width
|
||||
comment1.target=Simulator(int,\ int)
|
||||
comment1.text=\n\ Create\ a\ simulation\ field\ with\ the\ given\ size.\n\ @param\ depth\ Depth\ of\ the\ field.\ Must\ be\ greater\ than\ zero.\n\ @param\ width\ Width\ of\ the\ field.\ Must\ be\ greater\ than\ zero.\n
|
||||
comment2.params=
|
||||
comment2.target=void\ runLongSimulation()
|
||||
comment2.text=\n\ Run\ the\ simulation\ from\ its\ current\ state\ for\ a\ reasonably\ long\ period,\n\ (4000\ steps).\n
|
||||
comment3.params=numSteps
|
||||
comment3.target=void\ simulate(int)
|
||||
comment3.text=\n\ Run\ the\ simulation\ from\ its\ current\ state\ for\ the\ given\ number\ of\ steps.\n\ Stop\ before\ the\ given\ number\ of\ steps\ if\ it\ ceases\ to\ be\ viable.\n\ @param\ numSteps\ The\ number\ of\ steps\ to\ run\ for.\n
|
||||
comment4.params=
|
||||
comment4.target=void\ simulateOneStep()
|
||||
comment4.text=\n\ Run\ the\ simulation\ from\ its\ current\ state\ for\ a\ single\ step.\n\ Iterate\ over\ the\ whole\ field\ updating\ the\ state\ of\ each\n\ fox\ and\ rabbit.\n
|
||||
comment5.params=
|
||||
comment5.target=void\ reset()
|
||||
comment5.text=\n\ Reset\ the\ simulation\ to\ a\ starting\ position.\n
|
||||
comment6.params=
|
||||
comment6.target=void\ populate()
|
||||
comment6.text=\n\ Randomly\ populate\ the\ field\ with\ foxes\ and\ rabbits.\n
|
||||
comment7.params=millisec
|
||||
comment7.target=void\ delay(int)
|
||||
comment7.text=\n\ Pause\ for\ a\ given\ time.\n\ @param\ millisec\ \ The\ time\ to\ pause\ for,\ in\ milliseconds\n
|
||||
numComments=8
|
@@ -0,0 +1,167 @@
|
||||
import java.util.Random;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* A simple predator-prey simulator, based on a rectangular field
|
||||
* containing rabbits and foxes.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29 (2)
|
||||
*/
|
||||
public class Simulator
|
||||
{
|
||||
// Constants representing configuration information for the simulation.
|
||||
// The default width for the grid.
|
||||
private static final int DEFAULT_WIDTH = 120;
|
||||
// The default depth of the grid.
|
||||
private static final int DEFAULT_DEPTH = 80;
|
||||
// The probability that a fox will be created in any given grid position.
|
||||
private static final double FOX_CREATION_PROBABILITY = 0.02;
|
||||
// The probability that a rabbit will be created in any given grid position.
|
||||
private static final double RABBIT_CREATION_PROBABILITY = 0.08;
|
||||
|
||||
// List of animals in the field.
|
||||
private List<Animal> animals;
|
||||
// The current state of the field.
|
||||
private Field field;
|
||||
// The current step of the simulation.
|
||||
private int step;
|
||||
// A graphical view of the simulation.
|
||||
private SimulatorView view;
|
||||
|
||||
/**
|
||||
* Construct a simulation field with default size.
|
||||
*/
|
||||
public Simulator()
|
||||
{
|
||||
this(DEFAULT_DEPTH, DEFAULT_WIDTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a simulation field with the given size.
|
||||
* @param depth Depth of the field. Must be greater than zero.
|
||||
* @param width Width of the field. Must be greater than zero.
|
||||
*/
|
||||
public Simulator(int depth, int width)
|
||||
{
|
||||
if(width <= 0 || depth <= 0) {
|
||||
System.out.println("The dimensions must be greater than zero.");
|
||||
System.out.println("Using default values.");
|
||||
depth = DEFAULT_DEPTH;
|
||||
width = DEFAULT_WIDTH;
|
||||
}
|
||||
|
||||
animals = new ArrayList<>();
|
||||
field = new Field(depth, width);
|
||||
|
||||
// Create a view of the state of each location in the field.
|
||||
view = new SimulatorView(depth, width);
|
||||
view.setColor(Rabbit.class, Color.ORANGE);
|
||||
view.setColor(Fox.class, Color.BLUE);
|
||||
|
||||
// Setup a valid starting point.
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the simulation from its current state for a reasonably long period,
|
||||
* (4000 steps).
|
||||
*/
|
||||
public void runLongSimulation()
|
||||
{
|
||||
simulate(4000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the simulation from its current state for the given number of steps.
|
||||
* Stop before the given number of steps if it ceases to be viable.
|
||||
* @param numSteps The number of steps to run for.
|
||||
*/
|
||||
public void simulate(int numSteps)
|
||||
{
|
||||
for(int step = 1; step <= numSteps && view.isViable(field); step++) {
|
||||
simulateOneStep();
|
||||
// delay(60); // uncomment this to run more slowly
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the simulation from its current state for a single step.
|
||||
* Iterate over the whole field updating the state of each
|
||||
* fox and rabbit.
|
||||
*/
|
||||
public void simulateOneStep()
|
||||
{
|
||||
step++;
|
||||
|
||||
// Provide space for newborn animals.
|
||||
List<Animal> newAnimals = new ArrayList<>();
|
||||
// Let all rabbits act.
|
||||
for(Iterator<Animal> it = animals.iterator(); it.hasNext(); ) {
|
||||
Animal animal = it.next();
|
||||
animal.act(newAnimals);
|
||||
if(! animal.isAlive()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the newly born foxes and rabbits to the main lists.
|
||||
animals.addAll(newAnimals);
|
||||
|
||||
view.showStatus(step, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the simulation to a starting position.
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
step = 0;
|
||||
animals.clear();
|
||||
populate();
|
||||
|
||||
// Show the starting state in the view.
|
||||
view.showStatus(step, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly populate the field with foxes and rabbits.
|
||||
*/
|
||||
private void populate()
|
||||
{
|
||||
Random rand = Randomizer.getRandom();
|
||||
field.clear();
|
||||
for(int row = 0; row < field.getDepth(); row++) {
|
||||
for(int col = 0; col < field.getWidth(); col++) {
|
||||
if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
|
||||
Location location = new Location(row, col);
|
||||
Fox fox = new Fox(true, field, location);
|
||||
animals.add(fox);
|
||||
}
|
||||
else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
|
||||
Location location = new Location(row, col);
|
||||
Rabbit rabbit = new Rabbit(true, field, location);
|
||||
animals.add(rabbit);
|
||||
}
|
||||
// else leave the location empty.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause for a given time.
|
||||
* @param millisec The time to pause for, in milliseconds
|
||||
*/
|
||||
private void delay(int millisec)
|
||||
{
|
||||
try {
|
||||
Thread.sleep(millisec);
|
||||
}
|
||||
catch (InterruptedException ie) {
|
||||
// wake up
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
#BlueJ class context
|
||||
comment0.params=height\ width
|
||||
comment0.target=SimulatorView(int,\ int)
|
||||
comment0.text=\n\ Create\ a\ view\ of\ the\ given\ width\ and\ height.\n\ @param\ height\ The\ simulation's\ height.\n\ @param\ width\ \ The\ simulation's\ width.\n
|
||||
comment1.params=animalClass\ color
|
||||
comment1.target=void\ setColor(java.lang.Class,\ java.awt.Color)
|
||||
comment1.text=\n\ Define\ a\ color\ to\ be\ used\ for\ a\ given\ class\ of\ animal.\n\ @param\ animalClass\ The\ animal's\ Class\ object.\n\ @param\ color\ The\ color\ to\ be\ used\ for\ the\ given\ class.\n
|
||||
comment2.params=animalClass
|
||||
comment2.target=java.awt.Color\ getColor(java.lang.Class)
|
||||
comment2.text=\n\ @return\ The\ color\ to\ be\ used\ for\ a\ given\ class\ of\ animal.\n
|
||||
comment3.params=step\ field
|
||||
comment3.target=void\ showStatus(int,\ Field)
|
||||
comment3.text=\n\ Show\ the\ current\ status\ of\ the\ field.\n\ @param\ step\ Which\ iteration\ step\ it\ is.\n\ @param\ field\ The\ field\ whose\ status\ is\ to\ be\ displayed.\n
|
||||
comment4.params=field
|
||||
comment4.target=boolean\ isViable(Field)
|
||||
comment4.text=\n\ Determine\ whether\ the\ simulation\ should\ continue\ to\ run.\n\ @return\ true\ If\ there\ is\ more\ than\ one\ species\ alive.\n
|
||||
numComments=5
|
@@ -0,0 +1,215 @@
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A graphical view of the simulation grid.
|
||||
* The view displays a colored rectangle for each location
|
||||
* representing its contents. It uses a default background color.
|
||||
* Colors for each type of species can be defined using the
|
||||
* setColor method.
|
||||
*
|
||||
* @author David J. Barnes and Michael Kölling
|
||||
* @version 2016.02.29
|
||||
*/
|
||||
public class SimulatorView extends JFrame
|
||||
{
|
||||
// Colors used for empty locations.
|
||||
private static final Color EMPTY_COLOR = Color.white;
|
||||
|
||||
// Color used for objects that have no defined color.
|
||||
private static final Color UNKNOWN_COLOR = Color.gray;
|
||||
|
||||
private final String STEP_PREFIX = "Step: ";
|
||||
private final String POPULATION_PREFIX = "Population: ";
|
||||
private JLabel stepLabel, population;
|
||||
private FieldView fieldView;
|
||||
|
||||
// A map for storing colors for participants in the simulation
|
||||
private Map<Class, Color> colors;
|
||||
// A statistics object computing and storing simulation information
|
||||
private FieldStats stats;
|
||||
|
||||
/**
|
||||
* Create a view of the given width and height.
|
||||
* @param height The simulation's height.
|
||||
* @param width The simulation's width.
|
||||
*/
|
||||
public SimulatorView(int height, int width)
|
||||
{
|
||||
stats = new FieldStats();
|
||||
colors = new LinkedHashMap<>();
|
||||
|
||||
setTitle("Fox and Rabbit Simulation");
|
||||
stepLabel = new JLabel(STEP_PREFIX, JLabel.CENTER);
|
||||
population = new JLabel(POPULATION_PREFIX, JLabel.CENTER);
|
||||
|
||||
setLocation(100, 50);
|
||||
|
||||
fieldView = new FieldView(height, width);
|
||||
|
||||
Container contents = getContentPane();
|
||||
contents.add(stepLabel, BorderLayout.NORTH);
|
||||
contents.add(fieldView, BorderLayout.CENTER);
|
||||
contents.add(population, BorderLayout.SOUTH);
|
||||
pack();
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a color to be used for a given class of animal.
|
||||
* @param animalClass The animal's Class object.
|
||||
* @param color The color to be used for the given class.
|
||||
*/
|
||||
public void setColor(Class animalClass, Color color)
|
||||
{
|
||||
colors.put(animalClass, color);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The color to be used for a given class of animal.
|
||||
*/
|
||||
private Color getColor(Class animalClass)
|
||||
{
|
||||
Color col = colors.get(animalClass);
|
||||
if(col == null) {
|
||||
// no color defined for this class
|
||||
return UNKNOWN_COLOR;
|
||||
}
|
||||
else {
|
||||
return col;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the current status of the field.
|
||||
* @param step Which iteration step it is.
|
||||
* @param field The field whose status is to be displayed.
|
||||
*/
|
||||
public void showStatus(int step, Field field)
|
||||
{
|
||||
if(!isVisible()) {
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
stepLabel.setText(STEP_PREFIX + step);
|
||||
stats.reset();
|
||||
|
||||
fieldView.preparePaint();
|
||||
|
||||
for(int row = 0; row < field.getDepth(); row++) {
|
||||
for(int col = 0; col < field.getWidth(); col++) {
|
||||
Object animal = field.getObjectAt(row, col);
|
||||
if(animal != null) {
|
||||
stats.incrementCount(animal.getClass());
|
||||
fieldView.drawMark(col, row, getColor(animal.getClass()));
|
||||
}
|
||||
else {
|
||||
fieldView.drawMark(col, row, EMPTY_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
stats.countFinished();
|
||||
|
||||
population.setText(POPULATION_PREFIX + stats.getPopulationDetails(field));
|
||||
fieldView.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the simulation should continue to run.
|
||||
* @return true If there is more than one species alive.
|
||||
*/
|
||||
public boolean isViable(Field field)
|
||||
{
|
||||
return stats.isViable(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a graphical view of a rectangular field. This is
|
||||
* a nested class (a class defined inside a class) which
|
||||
* defines a custom component for the user interface. This
|
||||
* component displays the field.
|
||||
* This is rather advanced GUI stuff - you can ignore this
|
||||
* for your project if you like.
|
||||
*/
|
||||
private class FieldView extends JPanel
|
||||
{
|
||||
private final int GRID_VIEW_SCALING_FACTOR = 6;
|
||||
|
||||
private int gridWidth, gridHeight;
|
||||
private int xScale, yScale;
|
||||
Dimension size;
|
||||
private Graphics g;
|
||||
private Image fieldImage;
|
||||
|
||||
/**
|
||||
* Create a new FieldView component.
|
||||
*/
|
||||
public FieldView(int height, int width)
|
||||
{
|
||||
gridHeight = height;
|
||||
gridWidth = width;
|
||||
size = new Dimension(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the GUI manager how big we would like to be.
|
||||
*/
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(gridWidth * GRID_VIEW_SCALING_FACTOR,
|
||||
gridHeight * GRID_VIEW_SCALING_FACTOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for a new round of painting. Since the component
|
||||
* may be resized, compute the scaling factor again.
|
||||
*/
|
||||
public void preparePaint()
|
||||
{
|
||||
if(! size.equals(getSize())) { // if the size has changed...
|
||||
size = getSize();
|
||||
fieldImage = fieldView.createImage(size.width, size.height);
|
||||
g = fieldImage.getGraphics();
|
||||
|
||||
xScale = size.width / gridWidth;
|
||||
if(xScale < 1) {
|
||||
xScale = GRID_VIEW_SCALING_FACTOR;
|
||||
}
|
||||
yScale = size.height / gridHeight;
|
||||
if(yScale < 1) {
|
||||
yScale = GRID_VIEW_SCALING_FACTOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint on grid location on this field in a given color.
|
||||
*/
|
||||
public void drawMark(int x, int y, Color color)
|
||||
{
|
||||
g.setColor(color);
|
||||
g.fillRect(x * xScale, y * yScale, xScale-1, yScale-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The field view component needs to be redisplayed. Copy the
|
||||
* internal image to screen.
|
||||
*/
|
||||
public void paintComponent(Graphics g)
|
||||
{
|
||||
if(fieldImage != null) {
|
||||
Dimension currentSize = getSize();
|
||||
if(size.equals(currentSize)) {
|
||||
g.drawImage(fieldImage, 0, 0, null);
|
||||
}
|
||||
else {
|
||||
// Rescale the previous image.
|
||||
g.drawImage(fieldImage, 0, 0, currentSize.width, currentSize.height, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,180 @@
|
||||
#BlueJ package file
|
||||
dependency1.from=Field
|
||||
dependency1.to=Randomizer
|
||||
dependency1.type=UsesDependency
|
||||
dependency10.from=Rabbit
|
||||
dependency10.to=Randomizer
|
||||
dependency10.type=UsesDependency
|
||||
dependency11.from=Rabbit
|
||||
dependency11.to=Field
|
||||
dependency11.type=UsesDependency
|
||||
dependency12.from=Rabbit
|
||||
dependency12.to=Location
|
||||
dependency12.type=UsesDependency
|
||||
dependency13.from=FieldStats
|
||||
dependency13.to=Counter
|
||||
dependency13.type=UsesDependency
|
||||
dependency14.from=Simulator
|
||||
dependency14.to=Field
|
||||
dependency14.type=UsesDependency
|
||||
dependency15.from=Simulator
|
||||
dependency15.to=SimulatorView
|
||||
dependency15.type=UsesDependency
|
||||
dependency16.from=Simulator
|
||||
dependency16.to=Rabbit
|
||||
dependency16.type=UsesDependency
|
||||
dependency17.from=Simulator
|
||||
dependency17.to=Fox
|
||||
dependency17.type=UsesDependency
|
||||
dependency18.from=Simulator
|
||||
dependency18.to=Animal
|
||||
dependency18.type=UsesDependency
|
||||
dependency19.from=Simulator
|
||||
dependency19.to=Randomizer
|
||||
dependency19.type=UsesDependency
|
||||
dependency2.from=Field
|
||||
dependency2.to=Location
|
||||
dependency2.type=UsesDependency
|
||||
dependency20.from=Simulator
|
||||
dependency20.to=Location
|
||||
dependency20.type=UsesDependency
|
||||
dependency21.from=SimulatorView
|
||||
dependency21.to=FieldStats
|
||||
dependency21.type=UsesDependency
|
||||
dependency22.from=FieldStats
|
||||
dependency22.to=Field
|
||||
dependency22.type=UsesDependency
|
||||
dependency3.from=Animal
|
||||
dependency3.to=Field
|
||||
dependency3.type=UsesDependency
|
||||
dependency4.from=Animal
|
||||
dependency4.to=Location
|
||||
dependency4.type=UsesDependency
|
||||
dependency5.from=SimulatorView
|
||||
dependency5.to=Field
|
||||
dependency5.type=UsesDependency
|
||||
dependency6.from=Fox
|
||||
dependency6.to=Randomizer
|
||||
dependency6.type=UsesDependency
|
||||
dependency7.from=Fox
|
||||
dependency7.to=Field
|
||||
dependency7.type=UsesDependency
|
||||
dependency8.from=Fox
|
||||
dependency8.to=Location
|
||||
dependency8.type=UsesDependency
|
||||
dependency9.from=Fox
|
||||
dependency9.to=Rabbit
|
||||
dependency9.type=UsesDependency
|
||||
objectbench.height=76
|
||||
objectbench.width=1042
|
||||
package.editor.height=614
|
||||
package.editor.width=934
|
||||
package.editor.x=70
|
||||
package.editor.y=80
|
||||
package.numDependencies=22
|
||||
package.numTargets=10
|
||||
package.showExtends=true
|
||||
package.showUses=true
|
||||
project.charset=UTF-8
|
||||
target1.height=50
|
||||
target1.name=Field
|
||||
target1.naviview.expanded=true
|
||||
target1.showInterface=false
|
||||
target1.type=ClassTarget
|
||||
target1.typeParameters=
|
||||
target1.width=80
|
||||
target1.x=340
|
||||
target1.y=190
|
||||
target10.height=50
|
||||
target10.name=Location
|
||||
target10.naviview.expanded=true
|
||||
target10.showInterface=false
|
||||
target10.type=ClassTarget
|
||||
target10.typeParameters=
|
||||
target10.width=90
|
||||
target10.x=480
|
||||
target10.y=260
|
||||
target2.height=50
|
||||
target2.name=Randomizer
|
||||
target2.naviview.expanded=true
|
||||
target2.showInterface=false
|
||||
target2.type=ClassTarget
|
||||
target2.typeParameters=
|
||||
target2.width=90
|
||||
target2.x=480
|
||||
target2.y=530
|
||||
target3.height=50
|
||||
target3.name=Counter
|
||||
target3.naviview.expanded=true
|
||||
target3.showInterface=false
|
||||
target3.type=ClassTarget
|
||||
target3.typeParameters=
|
||||
target3.width=80
|
||||
target3.x=760
|
||||
target3.y=180
|
||||
target4.editor.height=700
|
||||
target4.editor.width=900
|
||||
target4.editor.x=342
|
||||
target4.editor.y=92
|
||||
target4.height=50
|
||||
target4.name=Animal
|
||||
target4.naviview.expanded=true
|
||||
target4.showInterface=false
|
||||
target4.type=AbstractTarget
|
||||
target4.typeParameters=
|
||||
target4.width=80
|
||||
target4.x=200
|
||||
target4.y=320
|
||||
target5.height=50
|
||||
target5.name=Rabbit
|
||||
target5.naviview.expanded=true
|
||||
target5.showInterface=false
|
||||
target5.type=ClassTarget
|
||||
target5.typeParameters=
|
||||
target5.width=80
|
||||
target5.x=140
|
||||
target5.y=470
|
||||
target6.editor.height=700
|
||||
target6.editor.width=900
|
||||
target6.editor.x=137
|
||||
target6.editor.y=97
|
||||
target6.height=50
|
||||
target6.name=SimulatorView
|
||||
target6.naviview.expanded=true
|
||||
target6.showInterface=false
|
||||
target6.type=ClassTarget
|
||||
target6.typeParameters=
|
||||
target6.width=110
|
||||
target6.x=540
|
||||
target6.y=40
|
||||
target7.editor.height=700
|
||||
target7.editor.width=900
|
||||
target7.editor.x=270
|
||||
target7.editor.y=93
|
||||
target7.height=50
|
||||
target7.name=Simulator
|
||||
target7.naviview.expanded=true
|
||||
target7.showInterface=false
|
||||
target7.type=ClassTarget
|
||||
target7.typeParameters=
|
||||
target7.width=80
|
||||
target7.x=70
|
||||
target7.y=110
|
||||
target8.height=50
|
||||
target8.name=Fox
|
||||
target8.naviview.expanded=true
|
||||
target8.showInterface=false
|
||||
target8.type=ClassTarget
|
||||
target8.typeParameters=
|
||||
target8.width=80
|
||||
target8.x=280
|
||||
target8.y=420
|
||||
target9.height=50
|
||||
target9.name=FieldStats
|
||||
target9.naviview.expanded=true
|
||||
target9.showInterface=false
|
||||
target9.type=ClassTarget
|
||||
target9.typeParameters=
|
||||
target9.width=80
|
||||
target9.x=660
|
||||
target9.y=120
|
Reference in New Issue
Block a user