Class Location:
Class Field:
Class FieldStats:
Class Randomizer
Class Counter:
Class Rabbit:
Class Fox:
Class Simulator:
Class SimulatorView:
Screenshot:
public class Location
{
private int row;
private int col;
public Location(int row, int col)
{
this.row = row;
this.col = col;
}
public boolean equals(Object obj)
{
if(obj instanceof Location) {
Location other = (Location) obj;
return row == other.getRow() && col == other.getCol();
}
else {
return false;
}
}
public String toString()
{
return row + "," + col;
}
public int hashCode()
{
return (row << 16) + col;
}
public int getRow()
{
return row;
}
public int getCol()
{
return col;
}
}
Class Field:
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
public class Field
{
private static final Random rand = Randomizer.getRandom();
private int depth, width;
private Object[][] field;
public Field(int depth, int width)
{
this.depth = depth;
this.width = width;
field = new Object[depth][width];
}
public void clear()
{
for(int row = 0; row < depth; row++) {
for(int col = 0; col < width; col++) {
field[row][col] = null;
}
}
}
public void clear(Location location)
{
field[location.getRow()][location.getCol()] = null;
}
public void place(Object animal, int row, int col)
{
place(animal, new Location(row, col));
}
public void place(Object animal, Location location)
{
field[location.getRow()][location.getCol()] = animal;
}
public Object getObjectAt(Location location)
{
return getObjectAt(location.getRow(), location.getCol());
}
public Object getObjectAt(int row, int col)
{
return field[row][col];
}
public Location randomAdjacentLocation(Location location)
{
List<Location> adjacent = adjacentLocations(location);
return adjacent.get(0);
}
public List<Location> getFreeAdjacentLocations(Location location)
{
List<Location> free = new LinkedList<Location>();
List<Location> adjacent = adjacentLocations(location);
for(Location next : adjacent) {
if(getObjectAt(next) == null) {
free.add(next);
}
}
return free;
}
public Location freeAdjacentLocation(Location location)
{
List<Location> free = getFreeAdjacentLocations(location);
if(free.size() > 0) {
return free.get(0);
}
else {
return null;
}
}
public List<Location> adjacentLocations(Location location)
{
assert location != null : "Null location passed to adjacentLocations";
List<Location> locations = new LinkedList<Location>();
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;
if(nextCol >= 0 && nextCol < width && (roffset != 0 || coffset != 0)) {
locations.add(new Location(nextRow, nextCol));
}
}
}
}
Collections.shuffle(locations, rand);
}
return locations;
}
public int getDepth()
{
return depth;
}
public int getWidth()
{
return width;
}
}
Class FieldStats:
import java.awt.Color;
import java.util.HashMap;
public class FieldStats
{
private HashMap<Class, Counter> counters;
private boolean countsValid;
public FieldStats()
{
counters = new HashMap<Class, Counter>();
countsValid = true;
}
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();
}
public void reset()
{
countsValid = false;
for(Class key : counters.keySet()) {
Counter count = counters.get(key);
count.reset();
}
}
public void incrementCount(Class animalClass)
{
Counter count = counters.get(animalClass);
if(count == null) {
count = new Counter(animalClass.getName());
counters.put(animalClass, count);
}
count.increment();
}
public void countFinished()
{
countsValid = true;
}
public boolean isViable(Field field)
{
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;
}
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;
}
}
Class Randomizer
import java.util.Random;
public class Randomizer
{
private static final int SEED = 1111;
private static final Random rand = new Random(SEED);
private static final boolean useShared = true;
public Randomizer()
{
}
public static Random getRandom()
{
if(useShared) {
return rand;
}
else {
return new Random();
}
}
public static void reset()
{
if(useShared) {
rand.setSeed(SEED);
}
}
}
Class Counter:
import java.awt.Color;
public class Counter
{
private String name;
private int count;
public Counter(String name)
{
this.name = name;
count = 0;
}
public String getName()
{
return name;
}
public int getCount()
{
return count;
}
public void increment()
{
count++;
}
public void reset()
{
count = 0;
}
}
Class Rabbit:
import java.util.List;
import java.util.Random;
public class Rabbit
{
private static final int BREEDING_AGE = 5;
private static final int MAX_AGE = 40;
private static final double BREEDING_PROBABILITY = 0.15;
private static final int MAX_LITTER_SIZE = 4;
private static final Random rand = Randomizer.getRandom();
private int age;
private boolean alive;
private Location location;
private Field field;
public Rabbit(boolean randomAge, Field field, Location location)
{
age = 0;
alive = true;
this.field = field;
setLocation(location);
if(randomAge) {
age = rand.nextInt(MAX_AGE);
}
}
public void run(List<Rabbit> newRabbits)
{
incrementAge();
if(alive) {
giveBirth(newRabbits);
Location newLocation = field.freeAdjacentLocation(location);
if(newLocation != null) {
setLocation(newLocation);
}
else {
setDead();
}
}
}
public boolean isAlive()
{
return alive;
}
public void setDead()
{
alive = false;
if(location != null) {
field.clear(location);
location = null;
field = null;
}
}
public Location getLocation()
{
return location;
}
private void setLocation(Location newLocation)
{
if(location != null) {
field.clear(location);
}
location = newLocation;
field.place(this, newLocation);
}
private void incrementAge()
{
age++;
if(age > MAX_AGE) {
setDead();
}
}
private void giveBirth(List<Rabbit> newRabbits)
{
List<Location> free = field.getFreeAdjacentLocations(location);
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);
}
}
private int breed()
{
int births = 0;
if(canBreed() && rand.nextDouble() <= BREEDING_PROBABILITY) {
births = rand.nextInt(MAX_LITTER_SIZE) + 1;
}
return births;
}
private boolean canBreed()
{
return age >= BREEDING_AGE;
}
}
Class Fox:
import java.util.List;
import java.util.Iterator;
import java.util.Random;
public class Fox
{
private static final int BREEDING_AGE = 10;
private static final int MAX_AGE = 150;
private static final double BREEDING_PROBABILITY = 0.35;
private static final int MAX_LITTER_SIZE = 5;
private static final int RABBIT_FOOD_VALUE = 7;
private static final Random rand = Randomizer.getRandom();
private int age;
private boolean alive;
private Location location;
private Field field;
private int foodLevel;
public Fox(boolean randomAge, Field field, Location location)
{
age = 0;
alive = true;
this.field = field;
setLocation(location);
if(randomAge) {
age = rand.nextInt(MAX_AGE);
foodLevel = rand.nextInt(RABBIT_FOOD_VALUE);
}
else {
foodLevel = RABBIT_FOOD_VALUE;
}
}
public void hunt(List<Fox> newFoxes)
{
incrementAge();
incrementHunger();
if(alive) {
giveBirth(newFoxes);
Location newLocation = findFood(location);
if(newLocation == null) {
newLocation = field.freeAdjacentLocation(location);
}
if(newLocation != null) {
setLocation(newLocation);
}
else {
setDead();
}
}
}
public boolean isAlive()
{
return alive;
}
public Location getLocation()
{
return location;
}
private void setLocation(Location newLocation)
{
if(location != null) {
field.clear(location);
}
location = newLocation;
field.place(this, newLocation);
}
private void incrementAge()
{
age++;
if(age > MAX_AGE) {
setDead();
}
}
private void incrementHunger()
{
foodLevel--;
if(foodLevel <= 0) {
setDead();
}
}
private Location findFood(Location location)
{
List<Location> adjacent = field.adjacentLocations(location);
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;
}
private void giveBirth(List<Fox> newFoxes)
{
List<Location> free = field.getFreeAdjacentLocations(location);
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);
}
}
private int breed()
{
int births = 0;
if(canBreed() && rand.nextDouble() <= BREEDING_PROBABILITY) {
births = rand.nextInt(MAX_LITTER_SIZE) + 1;
}
return births;
}
private boolean canBreed()
{
return age >= BREEDING_AGE;
}
private void setDead()
{
alive = false;
if(location != null) {
field.clear(location);
location = null;
field = null;
}
}
}
Class Simulator:
import java.util.Random;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.awt.Color;
public class Simulator
{
private static final int DEFAULT_WIDTH = 50;
private static final int DEFAULT_DEPTH = 50;
private static final double FOX_CREATION_PROBABILITY = 0.02;
private static final double RABBIT_CREATION_PROBABILITY = 0.08;
private List<Rabbit> rabbits;
private List<Fox> foxes;
private Field field;
private int step;
private SimulatorView view;
public Simulator()
{
this(DEFAULT_DEPTH, DEFAULT_WIDTH);
}
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;
}
rabbits = new ArrayList<Rabbit>();
foxes = new ArrayList<Fox>();
field = new Field(depth, width);
view = new SimulatorView(depth, width);
view.setColor(Rabbit.class, Color.orange);
view.setColor(Fox.class, Color.blue);
reset();
}
public void runLongSimulation()
{
simulate(500);
}
public void simulate(int numSteps)
{
for(int step = 1; step <= numSteps && view.isViable(field); step++) {
simulateOneStep();
}
}
public void simulateOneStep()
{
step++;
List<Rabbit> newRabbits = new ArrayList<Rabbit>();
for(Iterator<Rabbit> it = rabbits.iterator(); it.hasNext(); ) {
Rabbit rabbit = it.next();
rabbit.run(newRabbits);
if(! rabbit.isAlive()) {
it.remove();
}
}
List<Fox> newFoxes = new ArrayList<Fox>();
for(Iterator<Fox> it = foxes.iterator(); it.hasNext(); ) {
Fox fox = it.next();
fox.hunt(newFoxes);
if(! fox.isAlive()) {
it.remove();
}
}
rabbits.addAll(newRabbits);
foxes.addAll(newFoxes);
view.showStatus(step, field);
}
public void reset()
{
step = 0;
rabbits.clear();
foxes.clear();
populate();
view.showStatus(step, field);
}
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);
foxes.add(fox);
}
else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
Location location = new Location(row, col);
Rabbit rabbit = new Rabbit(true, field, location);
rabbits.add(rabbit);
}
}
}
}
}
Class SimulatorView:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.LinkedHashMap;
import java.util.Map;
public class SimulatorView extends JFrame
{
private static final Color EMPTY_COLOR = Color.white;
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;
private Map<Class, Color> colors;
private FieldStats stats;
public SimulatorView(int height, int width)
{
stats = new FieldStats();
colors = new LinkedHashMap<Class, Color>();
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);
}
public void setColor(Class animalClass, Color color)
{
colors.put(animalClass, color);
}
private Color getColor(Class animalClass)
{
Color col = colors.get(animalClass);
if(col == null) {
return UNKNOWN_COLOR;
}
else {
return col;
}
}
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();
}
public boolean isViable(Field field)
{
return stats.isViable(field);
}
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;
public FieldView(int height, int width)
{
gridHeight = height;
gridWidth = width;
size = new Dimension(0, 0);
}
public Dimension getPreferredSize()
{
return new Dimension(gridWidth * GRID_VIEW_SCALING_FACTOR,
gridHeight * GRID_VIEW_SCALING_FACTOR);
}
public void preparePaint()
{
if(! size.equals(getSize())) {
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;
}
}
}
public void drawMark(int x, int y, Color color)
{
g.setColor(color);
g.fillRect(x * xScale, y * yScale, xScale-1, yScale-1);
}
public void paintComponent(Graphics g)
{
if(fieldImage != null) {
Dimension currentSize = getSize();
if(size.equals(currentSize)) {
g.drawImage(fieldImage, 0, 0, null);
}
else {
g.drawImage(fieldImage, 0, 0, currentSize.width, currentSize.height, null);
}
}
}
}
}
Screenshot:
Komentar
Posting Komentar