/**
*
*/
package iamrescue.agent.police.newstrategy;
import iamrescue.agent.AbstractIAMAgent;
import iamrescue.belief.spatial.SpatialQueryFactory;
import iamrescue.execution.command.ClearCommand;
import iamrescue.execution.command.IPath;
import iamrescue.execution.command.MoveCommand;
import iamrescue.routing.AbstractRoutingModule;
import iamrescue.routing.costs.ClearingAndMovingRoutingFunction;
import iamrescue.routing.costs.IRoutingCostFunction;
import iamrescue.routing.dijkstra.SimpleDijkstrasRoutingModule;
import iamrescue.util.PositionXY;
import iamrescue.util.blocks.BlockDetectionUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import rescuecore2.standard.entities.Area;
import rescuecore2.standard.entities.Blockade;
import rescuecore2.standard.entities.PoliceForce;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.worldmodel.ChangeSet;
import rescuecore2.worldmodel.EntityID;
/**
* @author Sebastian
*
*/
public class CoordinatingClosestTargetPoliceForce extends
AbstractIAMAgent<PoliceForce> {
private static final String DISTANCE_KEY = "clear.repair.distance";
private static final int VERY_CLOSE = 2000;
private int clearDistance;
private int veryClose;
private static final double RECOMPUTE_THRESHOLD = 0.2;
private ClosestTargetAllocator taskAllocator;
private AbstractRoutingModule clearingModule;
private Collection<EntityID> refuges;
private static final Logger LOGGER = Logger
.getLogger(CoordinatingClosestTargetPoliceForce.class);
private double lastDistancePerTimeStep = 0;
private ChangeSet lastChanged;
private GoalGenerator goalGenerator;
@Override
protected void postConnect() {
super.postConnect();
IRoutingCostFunction clearingCostFunction = new ClearingAndMovingRoutingFunction(
getWorldModel(), config, getSpeedInfo());
clearingModule = new SimpleDijkstrasRoutingModule(getWorldModel(),
clearingCostFunction, getTimer());
taskAllocator = new ClosestTargetAllocator(getWorldModel());
lastDistancePerTimeStep = getSpeedInfo().getDistancePerTimeStep();
Collection<StandardEntity> refugeList = getWorldModel()
.getEntitiesOfType(StandardEntityURN.REFUGE);
refuges = new ArrayList<EntityID>(refugeList.size());
for (StandardEntity standardEntity : refugeList) {
refuges.add(standardEntity.getID());
}
clearDistance = config.getIntValue(DISTANCE_KEY);
veryClose = (VERY_CLOSE < clearDistance) ? VERY_CLOSE : clearDistance;
this.goalGenerator = new GoalGenerator(getWorldModel(), getTimer(),
config, getSpeedInfo());
// showRoutingViewer();
// showWorldModelViewer();
}
@Override
protected List<StandardEntityURN> getAgentTypes() {
return Collections.singletonList(StandardEntityURN.POLICE_FORCE);
}
@Override
protected void think(int time, ChangeSet changed) {
lastChanged = changed;
// checkRoutingRecompute();
boolean ok = false;
if (me().getDamage() > 0) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("I am damaged. Heading to refuge");
}
clearPathTo(refuges);
return;
}
Set<EntityID> stuckAgents = getWorldModel().getStuckMemory()
.getStuckAgents();
List<StandardEntity> stuckPositions = new ArrayList<StandardEntity>(
stuckAgents.size());
for (EntityID entityID : stuckAgents) {
stuckPositions.add(getWorldModel().getEntity(
getWorldModel().getStuckMemory().getStuckInfo(entityID)
.getPosition()));
}
taskAllocator.computeAllocation(stuckPositions, stuckAgents,
goalGenerator, me().getID());
StandardEntity closestGoal = null;
if (closestGoal != null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Heading towards goal "
+ closestGoal.getFullDescription());
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No valid goal found");
}
}
if (closestGoal != null) {
if (closestGoal.equals(me())) {
// Need to clear path to refuge
ok = clearPathTo(refuges);
} else {
ok = clearPathTo(closestGoal.getID());
}
}
if (!ok) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Doing searching instead.");
}
doDefaultSearch();
}
}
private void checkRoutingRecompute() {
double distancePerTimeStep = getSpeedInfo().getDistancePerTimeStep();
if (lastDistancePerTimeStep != 0
&& Math.abs(distancePerTimeStep - lastDistancePerTimeStep)
/ lastDistancePerTimeStep >= RECOMPUTE_THRESHOLD) {
long time = 0;
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Recomputing graph");
time = System.nanoTime();
}
Collection<StandardEntity> areas = getWorldModel()
.getEntitiesOfType(StandardEntityURN.ROAD,
StandardEntityURN.BUILDING,
StandardEntityURN.FIRE_STATION,
StandardEntityURN.POLICE_OFFICE,
StandardEntityURN.AMBULANCE_CENTRE,
StandardEntityURN.REFUGE);
for (StandardEntity area : areas) {
clearingModule.forceRecompute((Area) area);
}
lastDistancePerTimeStep = distancePerTimeStep;
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Recomputing graph took "
+ (System.nanoTime() - time) + "ns");
}
}
}
/**
* @param id
*/
private boolean clearPathTo(EntityID id) {
return clearPathTo(Collections.singleton(id));
}
private boolean clearPathTo(Collection<EntityID> targets) {
IPath path = clearingModule.findShortestPath(me().getID(), targets);
if (!path.isValid()) {
return false;
}
PositionXY myPosition = new PositionXY(me()
.getLocation(getWorldModel()));
List<Blockade> blocksToClear = BlockDetectionUtil
.findObstructingBlockades(path, getWorldModel());
Blockade blockToClear = null;
for (Blockade block : blocksToClear) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Block: " + block);
}
if (BlockDetectionUtil.isWithinDistanceToBlockade(myPosition,
block, clearDistance)) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("In range!");
}
if (lastChanged.getChangedEntities().contains(block.getID())) {
blockToClear = block;
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Found block on path to goal: "
+ blockToClear);
}
}
break;
} else {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Not in range: "
+ BlockDetectionUtil.getDistanceToBlockade(
myPosition, block));
}
}
}
if (blockToClear == null) {
// Check if very close to block
Collection<StandardEntity> objectsInRange = getWorldModel()
.getObjectsInRange(me(), veryClose);
for (StandardEntity entity : objectsInRange) {
if (entity instanceof Blockade) {
if (lastChanged.getChangedEntities().contains(
entity.getID())) {
blockToClear = (Blockade) entity;
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("I'm very close to a block: "
+ blockToClear);
}
break;
}
}
}
}
if (blockToClear != null) {
getExecutionService().execute(new ClearCommand(blockToClear));
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Moving towards goal: " + path.toVerboseString());
}
getExecutionService().execute(new MoveCommand(path));
}
return true;
}
/*
* (non-Javadoc)
*
* @see iamrescue.agent.AbstractIAMAgent#fallback(int,
* rescuecore2.worldmodel.ChangeSet)
*/
@Override
protected void fallback(int time, ChangeSet changed) {
doDefaultSearch();
}
}