/**
*
*/
package eas.users.students.christianNagel.coEvolutionChristian;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import eas.math.geometry.Polygon2D;
import eas.math.geometry.Vector2D;
import eas.simulation.Wink;
import eas.simulation.agent.AbstractAgent;
import eas.simulation.agent.GenericActuator;
import eas.simulation.agent.GenericSensor;
import eas.simulation.spatial.sim2D.standardAgents.AbstractAgent2D;
import eas.simulation.spatial.sim2D.standardEnvironments.AbstractEnvironment2D;
import eas.simulation.spatial.sim2D.standardEnvironments.CollisionData;
import eas.startSetup.ParCollection;
/**
* @author christiannagel
*/
public class WolfAgent extends AbstractAgent2D<CoEvolutionEnv> {
/**
*
*/
private static final long serialVersionUID = -6111455728314519216L;
private Polygon2D shape;
private double speed;
private double detectionRadius;
private double catchRadius;
private SheepAgent target;
@SuppressWarnings("unused")
private Random random;
private long lastTimeSheepChosen;
private int numberOfDistanceSensors;
private long lastTimeSheepCaught=0;
private HashSet<Long> catchReturnValues;
public WolfAgent(int id, CoEvolutionEnv env, double wolfSpeed, int numberOfDistanceSensors, double detectionRadius, double catchRadius, final Random random, ParCollection params) {
super(id, env, params);
this.speed=wolfSpeed;
this.detectionRadius=detectionRadius;
this.catchRadius=catchRadius;
this.random=random;
this.numberOfDistanceSensors = numberOfDistanceSensors;
for (int i =0; i<numberOfDistanceSensors; i++){
this.addSensor(new DistanceSensor(i));
}
this.addSensor(new GenericSensor<Integer, AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = -1409001473254012471L;
@Override
public String id() {
return "sensing-agent-0";
}
@Override
public Integer sense(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
int result = -1;
Vector2D angle= new Vector2D(env.getNormalizedLOV(agent.id()).x,env.getNormalizedLOV(agent.id()).y);
angle.rotate(Vector2D.NULL_VECTOR, -45+0*(90/(3-1.0))*Math.PI/180);
CollisionData coll = env.nearestRayCollision(
env.getAgentPosition(agent.id()),
angle,
agent);
if ((coll.getCollisionPoint()!=null&&coll.getCollisionPoint().distance(env.getAgentPosition(agent.id()))<15)){
result = coll.getAgent().id();
}
return result;
}
});
this.addSensor(new GenericSensor<Integer, AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = 187236060508880836L;
@Override
public String id() {
return "sensing-agent-1";
}
@Override
public Integer sense(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
int result = -1;
Vector2D angle= new Vector2D(env.getNormalizedLOV(agent.id()).x,env.getNormalizedLOV(agent.id()).y);
angle.rotate(Vector2D.NULL_VECTOR, -45+1*(90/(3-1.0))*Math.PI/180);
CollisionData coll = env.nearestRayCollision(
env.getAgentPosition(agent.id()),
angle,
agent);
if ((coll.getCollisionPoint()!=null&&coll.getCollisionPoint().distance(env.getAgentPosition(agent.id()))<15)){
result = coll.getAgent().id();
}
return result;
}
});
this.addSensor(new GenericSensor<Integer, AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = -2034243692637537731L;
@Override
public String id() {
return "sensing-agent-2";
}
@Override
public Integer sense(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
int result = -1;
Vector2D angle= new Vector2D(env.getNormalizedLOV(agent.id()).x,env.getNormalizedLOV(agent.id()).y);
angle.rotate(Vector2D.NULL_VECTOR, -45+2*(90/(3-1.0))*Math.PI/180);
CollisionData coll = env.nearestRayCollision(
env.getAgentPosition(agent.id()),
angle,
agent);
if ((coll.getCollisionPoint()!=null&&coll.getCollisionPoint().distance(env.getAgentPosition(agent.id()))<15)){
result = coll.getAgent().id();
}
return result;
}
});
this.addSensor(new GenericSensor<Boolean, AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = 3223404861645168405L;
@Override
public String id() {
return "sheepInDetectionRadius";
}
@Override
public Boolean sense(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
Boolean result=false;
double detectionRadius = ((WolfAgent) env.getAgent(agent.id())).getDetectionRadius();
for (AbstractAgent<?> agentX: env.getAgents() ){
double distance = env.getAgentPosition(agent.id()).distance(env.getAgentPosition(agentX.id()));
if (agentX.id()>=10 && agentX.id()%2==0 && distance<=detectionRadius){ //isSheepInSight
result=true;
break;
}
}
return result;
}
});
this.addSensor(new GenericSensor<Vector2D, AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = -3733776000131900630L;
@Override
public String id() {
return "targetPositionInDetectionRadius";
}
@Override
public Vector2D sense(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
Vector2D result=null;
double detectionRadius = ((WolfAgent) env.getAgent(agent.id())).getDetectionRadius();
if (target!=null){
double distance = env.getAgentPosition(agent.id()).distance(env.getAgentPosition(target.id()));
if(target!=null && target.id()>=10 && target.id()%2==0 && distance<=detectionRadius){
result=env.getAgentPosition(target.id());
}
}
return result;
}
});
this.addSensor(new GenericSensor<Integer, AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = 1300915943928511209L;
@Override
public String id() {
return "targetID";
}
@Override
public Integer sense(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
int result=-1;
if(target!=null){
result=target.id();
}
return result;
}
});
this.addActuator(new GenericActuator<CoEvolutionEnv, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = -5017791341484085564L;
@Override
public String id() {
return "drive";
}
@Override
public void actuate(CoEvolutionEnv env, AbstractAgent2D<?> agent) {
if(env.differentialDriveForward(agent.id())){
//no collision
} else{
env.unfallSimulation(env.getAgent(agent.id()),360);
}
}
});
this.addActuator(new GenericActuator<AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = -6021940550682006287L;
@Override
public String id() {
return "chooseSheep";
}
@Override
public void actuate(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
List<AbstractAgent<?>> sheepAgentsInSight = new LinkedList<AbstractAgent<?>>();
double detectionRadius = ((WolfAgent) env.getAgent(agent.id())).getDetectionRadius();
for (AbstractAgent<?> agentX: env.getAgents() ){
double distance = env.getAgentPosition(agent.id()).distance(env.getAgentPosition(agentX.id()));
if (agentX.id()>=10 && agentX.id()%2==0 && distance<=detectionRadius){ //isSheepInSight
sheepAgentsInSight.add(agentX);
}
}
SheepAgent targetSheep;
if (sheepAgentsInSight.size()==0){
targetSheep=null;
}
else{
targetSheep = (SheepAgent) sheepAgentsInSight.get(random.nextInt(sheepAgentsInSight.size()));
}
target = targetSheep;
}
});
this.addActuator(new GenericActuator<AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = 7636597494956377900L;
@Override
public String id() {
return "focus";
}
@Override
public void actuate(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
if (target!=null){
Vector2D ownPosition = env.getAgentPosition(agent.id());
Vector2D targetPosition = env.getAgentPosition(target.id());
Vector2D direction = new Vector2D(-ownPosition.x+targetPosition.x,-ownPosition.y+targetPosition.y);
double angle = new Vector2D (0,-1).angle(direction)*180/Math.PI;
if (targetPosition.x<ownPosition.x){
env.setAgentAngle(agent.id(), 180-angle);
}
else{
env.setAgentAngle(agent.id(), 180+angle);
}
}
}
});
this.addActuator(new GenericActuator<AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = -468119785924419114L;
@Override
public String id() {
return "avoid-collision";
}
@Override
public void actuate(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
env.differentialDriveBackward(agent.id());
}
});
this.addActuator(new GenericActuator<AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = 7180465767124900868L;
@Override
public String id() {
return "change-angle";
}
@Override
public void actuate(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
double randomAngle = random.nextDouble()*360;
env.setAgentAngle(agent.id(), randomAngle);
}
});
this.addActuator(new GenericActuator<CoEvolutionEnv, AbstractAgent2D<?>>() {
/**
*
*/
private static final long serialVersionUID = -5762477080882311524L;
@Override
public String id() {
return "catchSheepIfPossible";
}
@Override
public void actuate(CoEvolutionEnv env, AbstractAgent2D<?> agent) {
SheepAgent randomReachedSheepAgent;
if (target!=null&&env.getAgentPosition(agent.id()).distance(env.getAgentPosition(target.id()))<=((WolfAgent)agent).getCatchRadius()){
long now = env.getSimTime().getCurrentTime().getLastTick();
if (catchReturnValues==null){
catchReturnValues = new HashSet<Long>();
}
catchReturnValues.add(now - lastTimeSheepCaught); //add new catch record using autoboxing
lastTimeSheepCaught = now;
env.replaceBrain(target.id(), random);
env.setRandomPosition(target.id(), random);
target=null;
} else if (env.getAgentPosition(agent.id()).distance(env.getAgentPosition(env.nearestAgent(agent).id()))<=((WolfAgent)agent).getCatchRadius()
&& env.nearestAgent(agent).id()%2==0
&& env.nearestAgent(agent).id()>=10){
randomReachedSheepAgent =(SheepAgent) env.nearestAgent(agent);
long now = env.getSimTime().getCurrentTime().getLastTick();
if (catchReturnValues==null){
catchReturnValues = new HashSet<Long>();
}
catchReturnValues.add(now - lastTimeSheepCaught); //add new catch record using autoboxing
lastTimeSheepCaught = now;
env.replaceBrain(randomReachedSheepAgent.id(), random);
env.setRandomPosition(randomReachedSheepAgent.id(), random);
}
}
});
this.shape = new Polygon2D();
this.shape.add(new Vector2D(-.5, .5));
this.shape.add(new Vector2D(0, 0));
this.shape.add(new Vector2D(.5, .5));
this.shape.add(new Vector2D(.5, -.5));
this.shape.add(new Vector2D(-.5, -.5));
}
class DistanceSensor extends GenericSensor<Double, AbstractEnvironment2D<AbstractAgent2D<?>>, AbstractAgent2D<?>>{
/**
*
*/
private static final long serialVersionUID = 3251515753033343243L;
int sensorNumber;
DistanceSensor(int sensorNumber){
this.sensorNumber=sensorNumber;
}
@Override
public String id() {
return "distance-" + sensorNumber;
}
@Override
public Double sense(AbstractEnvironment2D<AbstractAgent2D<?>> env, AbstractAgent2D<?> agent) {
Vector2D angle= new Vector2D(env.getNormalizedLOV(agent.id()).x,env.getNormalizedLOV(agent.id()).y);
if (numberOfDistanceSensors>1)
angle.rotate(Vector2D.NULL_VECTOR, -45+sensorNumber*(90/(numberOfDistanceSensors-1.0))*Math.PI/180);
Vector2D poi = env.nearestRayCollision(
env.getAgentPosition(agent.id()),
angle,
agent).getCollisionPoint();
if (poi == null) {
return Double.POSITIVE_INFINITY;
} else{
return env.getAgentPosition(agent.id()).distance(poi);
}
}
}
@SuppressWarnings("rawtypes")
@Override
public void step(final Wink simTime) {
super.step(simTime);
long currentTime;
if ((Boolean)this.sense("sheepInDetectionRadius")){
if((currentTime=this.getEnvironment().getSimTime().getCurrentTime().getLastTick()) - lastTimeSheepChosen > ((AbstractEnvironment2D) this.getEnvironment()).getParCollection().getParValueLong("chooseSheepInterval")){
this.actuate("chooseSheep");
lastTimeSheepChosen = currentTime;
}
this.actuate("focus");
}
if(
(
(((Integer)this.sense("sensing-agent-0")<10 &&
(Integer)this.sense("sensing-agent-0")>-1) ||
(Integer)this.sense("sensing-agent-0")%2==1) && (Double)this.sense("distance-0")<10
)
||
(
(((Integer)this.sense("sensing-agent-1")<10 &&
(Integer)this.sense("sensing-agent-1")>-1) ||
(Integer)this.sense("sensing-agent-1")%2==1) && (Double)this.sense("distance-1")<10
)
||
(
(((Integer)this.sense("sensing-agent-2")<10 &&
(Integer)this.sense("sensing-agent-2")>-1) ||
(Integer)this.sense("sensing-agent-2")%2==1) && (Double)this.sense("distance-2")<10
)
){
this.actuate("avoid-collision");
this.actuate("change-angle");
this.actuate("drive");
} else{
((AbstractEnvironment2D) this.getEnvironment()).setWheelSpeedLeft(this.id(), speed);
((AbstractEnvironment2D) this.getEnvironment()).setWheelSpeedRight(this.id(), speed);
this.actuate("drive");
}
this.actuate("catchSheepIfPossible");
}
@Override
public Polygon2D getAgentShape() {
return shape;
}
/**
* @return Returns the speed.
*/
public double getSpeed() {
return speed;
}
/**
* @return Returns the detectionRadius.
*/
public double getDetectionRadius() {
return detectionRadius;
}
/**
* @return Returns the catchRadius.
*/
public double getCatchRadius() {
return catchRadius;
}
/**
* @param target The target to set.
*/
public void setTarget(SheepAgent target) {
this.target = target;
}
/**
* @return Returns the target.
*/
public SheepAgent getTarget() {
return target;
}
/**
* @return lastAverageTimeToCatch
*/
public long getLastTimeToCatch() {
long result;
if (catchReturnValues == null){
result =-1;
}
else{
long sum = 0;
for (Long value: catchReturnValues){
sum += value; //using auto-unboxing
}
result = sum/catchReturnValues.size();
catchReturnValues = null;
}
return result;
}
}