/// <summary>
/// Moves all agents in the world forward by one step and collects food for any agents on top of
/// a plant.
/// </summary>
public void Step()
{
// If no one set a lookup table yet, generate one.
if (_sensorDictionary == null)
{
_sensorDictionary = new SensorDictionary((int)AgentHorizon, Height, Width);
}
// Advance each teacher by one step
foreach (var agent in Agents)
{
var sensors = calculateForagingAgentSensors(agent);
agent.Step(sensors);
applyToroidalAgentLocationRules(agent);
}
// Advance each predator by one step
foreach (var predator in Predators)
{
var sensors = calculatePredatorSensors(predator);
predator.Step(sensors);
applyToroidalAgentLocationRules(predator);
}
// Make a separate pass over all the agents, now that they're in new locations
// and determine who is on top of a plant and who is on top of a predator.
foreach (var agent in Agents)
{
foreach (var predator in Predators)
{
if (agent.HidingMode != predator.AttackType &&
_sensorDictionary.getDistanceAndOrientation((int)agent.X, (int)agent.Y, (int)predator.X, (int)predator.Y)[0]
< agent.Radius && !agent.EatenByRecently(_step, AGENT_GHOST_TIME, predator))
{
// Eat the agent
agent.EatenBy(predator, _step);
// Notify the predator that it received a reward
predator.ReceiveReward(agent.Reward);
// Notify the agent that it's been eaten.
agent.ReceiveReward(-agent.Reward);
// Notify listeners that we gobbled up this agent
onAgentEaten(predator, agent);
}
}
foreach (var plant in Plants)
{
if (_sensorDictionary.getDistanceAndOrientation((int)agent.X, (int)agent.Y, (int)plant.X, (int)plant.Y)[0]
< plant.Radius && plant.AvailableForEating(agent))
{
// Eat the plant
plant.EatenBy(agent, _step);
// Notify the teacher that it received a reward
agent.ReceiveReward(plant.Reward);
// Notify listeners that someone has eaten a plant.
onPlantEaten(agent, plant);
}
}
agent.Fitness += StepReward;
}
// Notify listeners that the world has stepped and changed.
onStepped(EventArgs.Empty);
onChanged(EventArgs.Empty);
_step++;
}