/*
* Bee foraging simulation. Copyright by Joerg Hoehne.
* For suggestions or questions email me at hoehne@thinktel.de
*/
package masonGlue;
import java.awt.Color;
import java.util.ListIterator;
import java.util.Vector;
import javax.vecmath.Point3d;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.field.continuous.Continuous2D;
import sim.util.Bag;
import sim.util.Double2D;
import foragingBee.Bee;
import foragingBee.FoodSource;
import foragingBee.Hive;
import foragingBee.HiveEntrance;
import foragingBee.IAgentLocator;
import foragingBee.IMovingAgent;
import foragingBee.Obstacle;
/**
* This class hold all information for the simulation. This class implements the
* simulated world of a hive ({@link Hive}), bees ({@link Bee}) and food sources
* ({@link FoodSource}). This class does not provide any user interface.
* <p>
* This class implements {@link Steppable} and extends the type {@link SimState}
* . Invoking the method {@link #step(SimState)} will provide an instance of
* this class.
* <p>
* Copyright 2009 Joerg Hoehne
*
* @author hoehne (<a href="mailto:hoehne@thinktel.de">Jörg Höhne</a>)
*
*/
public class ForagingHoneyBeeSimulation extends SimState implements Steppable,
IAgentLocator {
/**
* The minimum x bounds.
*/
static public final int X_MIN = 0;
/**
* The maximum x bounds exclusive.
*/
static public final int X_MAX = 400;
/**
* The minimum y bounds.
*/
static public final int Y_MIN = 0;
/**
* The maximum y bounds exclusive.
*/
static public final int Y_MAX = 400;
/**
* The minimum z bounds.
*/
static public final int Z_MIN = 0;
/**
* The maximum z bounds exclusive.
*/
static public final int Z_MAX = 400;
/**
* The width (x axis).
*/
static public final int WIDTH = X_MAX - X_MIN;
/**
* The height (y axis).
*/
static public final int HEIGHT = Y_MAX - Y_MIN;
/**
* The length (z axis).
*/
static public final int LENGTH = Z_MAX - Z_MIN;
/**
* The diameter of the hive.
*/
static public final double HIVE_DIAMETER = 80;
/**
* Set it to true if obstacles (other agents) are to be avoided.
*/
public boolean avoidObstacles = false;
/**
* The maximum number of bees in the simulation. This value is defined
* protected only because a parametrizing subclass has to access this
* property.
*/
public int maxBees = 800;
/**
* The communication problems between bees. It is noise when transferring
* information.
*/
public double comNoise = 0.01;
/**
* A value describing the probability a bee forgets its source in every
* iteration step.
*/
public double pForgettingSource = 30E-6;
/**
* A value describing the probability to start scouting.
*
*/
public double pStartScouting = 39E-6;
/**
* A value describing the probability to forage again if the be returned
* from foraging.
*
*/
public double pForagingAgain = 500E-6;
/**
* The general urge the colony needs some nectar. This is a highly
* aggregated variable including several aspects.
*/
public double colonyNectarNeed = 0.5;
/**
* A value describing the maximum steps for a bee searching a food source.
*/
public int maxSearchSteps = 100;
/**
* The maximum sphere radius of all objects in the simulation.
*/
double maxAgentSphereRadius = Double.MIN_VALUE;
/**
* All agents in the simulation.
*/
Vector<IMovingAgent> agents = new Vector<IMovingAgent>();
/**
* All hives of type {@link Hive} in the simulation.
*/
Vector<Hive> hives = new Vector<Hive>();
/**
* All food sources of type {@link FoodSource} in the simulation.
*/
Vector<FoodSource> foodSources = new Vector<FoodSource>();
/**
* All obstacles of type {@link Obstacle} in the simulation.
*/
Vector<Obstacle> obstacles = new Vector<Obstacle>();
/**
*
*/
private static final long serialVersionUID = -2187248402977949189L;
/**
* An environment the agents are moving in. This object has to be created in
* an early stage because it will referenced during the creation of agents
* because on creation agents will update their location. The locations are
* stored in the {@link #environment} object.
*/
public Continuous2D environment = new Continuous2D(100, WIDTH, HEIGHT);
/**
* The public constructor. Takes a seed for initializing the random number
* generator and also a parameter set.
*
* @param seed
*/
public ForagingHoneyBeeSimulation(long seed) {
super(seed);
prepareSimulation();
}
/**
* Overwritten method for execution of this {@link SimState} object.
*/
public void start() {
super.start();
// initialize the simulation
initSimulation();
// add this simulation to the scheduler
schedule.scheduleRepeating(this);
}
/**
* This method is performed when the next step for the simulation is
* computed. This simulation does nothing, so nothing is inside the body of
* the method.
* <p>
* This method is used because this object is placed in the scheduler.
*
*
* @param state
* The {@link SimState} environment, in this simulation an
* instance of type {@link ForagingHoneyBeeSimulation} or
* {@link ParametrizedForagingHoneyBeeSimulation}.
*/
public void step(SimState state) {
}
/**
* This method prepares the simulation by creating all necessary objects.
* This step is not really necessary because this can be done in the method
* {@link #start()} that is called prior executing the simulation. But to
* provide ready initialized objects for an user interface an even prior
* call is a precondition so the objects are instantiated before even
* {@link #start()} is called because the user interface and a model
* inspector are created before calling {@link #start()}.
*/
private void prepareSimulation() {
// FIXME z coordinate is zero, should be LENGTH/2
// create the hive
Hive hive = new Hive(this, new Point3d(50, 50, 0), HIVE_DIAMETER, 5000);
addAgent(hive);
// create the entrance
HiveEntrance entrance = new HiveEntrance(this, hive, 0);
hive.setEntrance(entrance);
addAgent(entrance);
FoodSource f1 = new FoodSource(this, new Point3d(300, 100, 0), 20,
new Color(0xd0, 0x00, 0x00), 100);
addAgent(f1);
FoodSource f2 = new FoodSource(this, new Point3d(50, 350, 0), 15,
new Color(0xff, 0x80, 0x80), 200);
addAgent(f2);
FoodSource f3 = new FoodSource(this, new Point3d(200, 200, 0), 35,
new Color(0xd0, 0x00, 0xd0), 300);
addAgent(f3);
FoodSource f4 = new FoodSource(this, new Point3d(180, 250, 0), 18,
new Color(0x00, 0xd0, 0xd0), 300);
addAgent(f4);
Obstacle o = new Obstacle(this, new Point3d(155, 130, 0), 20);
addAgent(o);
}
/**
* This method will be called by the {@link #start()} method that will start
* the simulation. The agents are created and placed into the simulation.
* The method {@link #prepareSimulation()} is called first to prepare the
* simulation and provide the user interface with data.
* <p>
* This method places <b>every</b> agent in the scheduler, even those that
* are created in {@link #prepareSimulation()}.
*/
private void initSimulation() {
/*
* If a hive exists create the maximum number of bees.
*/
Hive hive = hives.get(0);
if (hive != null) {
Point3d fsl = hive.getLocation();
int i;
for (i = 0; i < maxBees; i++) {
Bee b = new Bee(this, hive, new Point3d(fsl.x, fsl.y, 0));
addAgent(b);
}
}
/**
* Place *every* agent in the scheduler.
*/
ListIterator<IMovingAgent> li;
li = agents.listIterator();
while (li.hasNext()) {
schedule.scheduleRepeating((Steppable) li.next());
}
}
/**
* Check if the center of the agent is outside the simulation bounds. For
* every bound on the axis it is checked if it is below the minimum or above
* or equal the maximum: the maximum value is outside.
*
* @param agent
* @return True if the agent is outside the boundaries.
*/
public boolean isOutside(IMovingAgent agent) {
Point3d l = agent.getLocation();
return ((l.x < X_MIN) | (l.x >= X_MAX) | (l.y < Y_MIN) | (l.y >= Y_MAX)
| (l.z < Z_MIN) | (l.z >= Z_MAX));
}
/**
* Add an agent to the simulation. The maximum sphere of all objects is
* computed during successfully adding an agent. Some agent classes are
* additionally stored in list to provide access in the user interface.
*
* @param agent
* @return True, if the agent has successfully added; false otherwise.
*/
public boolean addAgent(IMovingAgent agent) {
if (!agents.contains(agent)) {
agents.add(agent);
if (agent instanceof Hive) {
hives.add((Hive) agent);
}
if (agent instanceof FoodSource) {
foodSources.add((FoodSource) agent);
}
if (agent instanceof Obstacle)
obstacles.add((Obstacle) agent);
double r = agent.getSphereRadius();
if (r > maxAgentSphereRadius)
maxAgentSphereRadius = r;
return true;
}
return false;
}
/**
* Remove an agent from the simulation. If the agent has a sphere which
* represents the maximum radius of all agents spheres the (possible) new
* maximum sphere is computed.
* <p>
* The agents are also removed from the additional lists if necessary.
*
* @param agent
* @return True if the agent has been removed, false otherwise (because it
* has never been stored).
*/
public boolean removeAgent(IMovingAgent agent) {
boolean status = agents.remove(agent);
if (agent instanceof Hive)
hives.remove(agent);
if (agent instanceof FoodSource)
foodSources.remove(agent);
if (agent instanceof Obstacle)
obstacles.remove(agent);
if (status) {
double radius = agent.getSphereRadius();
if (radius >= maxAgentSphereRadius) {
maxAgentSphereRadius = computeMaxAgentSphereRadius();
}
}
return status;
}
/**
* Compute the maximum radius of all agents inside this simulation.
*
* @return The computed maximum sphere currently in the simulation.
*/
private double computeMaxAgentSphereRadius() {
double max = Double.MIN_VALUE;
double r;
ListIterator<IMovingAgent> li = agents.listIterator();
while (li.hasNext()) {
r = li.next().getSphereRadius();
if (r > max)
max = r;
}
return max;
}
/**
* This is a basic glue method demanded by the {@link IAgentLocator}
* interface. This method allows every agent to inform the simulation about
* a change in the agents location.
*
* @param agent
* The agent whose location has to be updated.
*/
public void updateLocation(IMovingAgent agent) {
Point3d location = agent.getLocation();
environment.setObjectLocation(agent, new Double2D(location.x,
location.y));
}
/**
* Compute every agent that is within a certain location from an agent. This
* method assumes all objects are points so only the objects. Due to the
* algorithm provided by MASON objects with a distance at least as provided
* are included.
*
* @param agent
* The agent where to start.
* @param distance
* The distance (radius) the returned agents should lie within.
* @return All objects that are at least in the distance.
*/
public Object[] getObjectsWithinDistance(IMovingAgent agent, double distance) {
Point3d location = agent.getLocation();
Bag b = environment.getObjectsWithinDistance(new Double2D(location.x,
location.y), distance, false, false);
return b.toArray();
}
/**
* Return the maximum radius of all agents inside this simulation.
*
* @return The current maximum sphere.
*/
public double getMaxSphereRadius() {
return this.maxAgentSphereRadius;
}
}