package iamrescue.agent.police.newstrategy;
import iamrescue.agent.ISimulationTimer;
import iamrescue.belief.IAMWorldModel;
import iamrescue.execution.command.IPath;
import iamrescue.routing.WorldModelConverter;
import iamrescue.routing.WorldModelConverter.SimpleGraphNode;
import iamrescue.routing.WorldModelConverter.WorldModelArea;
import iamrescue.routing.costs.IRoutingCostFunction;
import iamrescue.routing.costs.PassableRoutingCostFunction;
import iamrescue.routing.dijkstra.DijkstrasShortestPath;
import iamrescue.routing.dijkstra.SimpleDijkstrasRoutingModule;
import iamrescue.routing.dijkstra.SimpleGraph;
import iamrescue.routing.util.ISpeedInfo;
import iamrescue.util.PositionXY;
import iamrescue.util.comparators.EntityIDComparator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javolution.util.FastList;
import javolution.util.FastMap;
import javolution.util.FastSet;
import rescuecore2.config.Config;
import rescuecore2.standard.entities.Area;
import rescuecore2.standard.entities.Building;
import rescuecore2.standard.entities.Civilian;
import rescuecore2.standard.entities.Human;
import rescuecore2.standard.entities.PoliceForce;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.WorldModel;
import rescuecore2.worldmodel.WorldModelListener;
public class AllAgentTaskAllocator implements
WorldModelListener<StandardEntity> {
private FutureClearingRoutingModule clearingModule;// = new
private Config config;
private ISimulationTimer timer;
private IAMWorldModel worldModel;
private List<StandardEntity> otherAgents;
private List<StandardEntity> policeForces;
private List<StandardEntity> civilians;
private SimpleDijkstrasRoutingModule freeRouting;
private IRoutingCostFunction freeRoutingCostFunction;
private List<StandardEntity> refuges;
private ArrayList<Integer> refugeSourceList;
private ArrayList<Double> refugeCostList;
// What each police agent is working on.
private EntityID[] workingOn;
// My index in police forces list
private int myIndex;
// Predicted completion time of each goal currently attempted.
private Map<EntityID, Integer> completionTimes = new FastMap<EntityID, Integer>();
// FutureClearingRoutingModule(config,
// timer, worldModel,
// myID);
public AllAgentTaskAllocator(IAMWorldModel worldModel,
ISimulationTimer timer, Config config, EntityID myID,
ISpeedInfo speedInfo) {
clearingModule = new FutureClearingRoutingModule(config, timer,
worldModel, speedInfo);
this.worldModel = worldModel;
this.timer = timer;
this.config = config;
this.freeRoutingCostFunction = new PassableRoutingCostFunction(1,
Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, worldModel);
this.freeRouting = new SimpleDijkstrasRoutingModule(worldModel,
freeRoutingCostFunction, timer);
// this.myID = myID;
// Get all police agents
policeForces = new ArrayList<StandardEntity>();
policeForces.addAll(worldModel
.getEntitiesOfType(StandardEntityURN.POLICE_FORCE));
workingOn = new EntityID[policeForces.size()];
for (int i = 0; i < workingOn.length; i++) {
// Initially no-one is working on anything.
workingOn[i] = null;
}
// Get other agents
otherAgents = new ArrayList<StandardEntity>();
otherAgents.addAll(worldModel.getEntitiesOfType(
StandardEntityURN.AMBULANCE_TEAM,
StandardEntityURN.FIRE_BRIGADE));
// Civilians
civilians = new ArrayList<StandardEntity>();
civilians.addAll(worldModel
.getEntitiesOfType(StandardEntityURN.CIVILIAN));
refuges = new ArrayList<StandardEntity>();
refuges.addAll(worldModel.getEntitiesOfType(StandardEntityURN.REFUGE));
// Sort all
Collections.sort(policeForces, EntityIDComparator.DEFAULT_INSTANCE);
Collections.sort(otherAgents, EntityIDComparator.DEFAULT_INSTANCE);
Collections.sort(civilians, EntityIDComparator.DEFAULT_INSTANCE);
Collections.sort(refuges, EntityIDComparator.DEFAULT_INSTANCE);
myIndex = Collections.binarySearch(policeForces, worldModel
.getEntity(myID), new EntityIDComparator());
worldModel.addWorldModelListener(this);
// Extract converter
WorldModelConverter converter = freeRouting.getConverter();
// Get all sources
Set<Integer> sources = new FastSet<Integer>();
for (StandardEntity refuge : refuges) {
WorldModelArea worldModelArea = converter.getWorldModelArea(refuge
.getID().getValue());
sources.addAll(worldModelArea.getSimpleNeighbours());
}
refugeSourceList = new ArrayList<Integer>(sources.size());
refugeCostList = new ArrayList<Double>(sources.size());
for (Integer id : sources) {
refugeSourceList.add(id);
refugeCostList.add(0.0);
}
}
public IPath computeBestPath(PoliceForce me) {
// Compute new cost function
clearingModule.recomputeAll();
// Allocate for all police agents
for (int i = 0; i < policeForces.size(); i++) {
SimpleGraph routingGraph = clearingModule.getRoutingGraph();
WorldModelConverter converter = clearingModule.getConverter();
// Work out start positions
PoliceForce police = (PoliceForce) policeForces.get(i);
if (!police.isPositionDefined()) {
// skip
continue;
}
Area position = (Area) worldModel.getEntity(police.getPosition());
PositionXY xy = new PositionXY(police.getLocation(worldModel));
List<Integer> startPositions = new FastList<Integer>();
List<Double> startCosts = new FastList<Double>();
Set<Integer> simpleGraphIDs = converter.getSimpleGraphIDs(police
.getPosition().getValue());
for (int id : simpleGraphIDs) {
startPositions.add(i);
clearingModule.getRoutingCostFunction().getTravelCost(
position,
xy,
converter.getSimpleGraphNode(id)
.getRepresentativePoint());
}
// DijkstrasShortestPath dijkstra = new
// DijkstrasShortestPath(routingGraph, )
}
return null;
}
public StandardEntity computeClosestGoal(PoliceForce police) {
// Generate goals
GoalContainer generatedGoals = generateGoals();
PositionXY myPosition = new PositionXY(police.getLocation(worldModel));
double bestDistance = Double.POSITIVE_INFINITY;
StandardEntity best = null;
Collection<List<? extends StandardEntity>> potentialGoals = new FastList<List<? extends StandardEntity>>();
potentialGoals.add(generatedGoals.getBlockedAgents());
potentialGoals.add(generatedGoals.getBlockedCivilians());
potentialGoals.add(generatedGoals.getBlockedBurningBuildings());
potentialGoals.add(generatedGoals.getBlockedUnsearchedBuildings());
// Clear all remaining blockades.
/*
* FastList<StandardEntity> blockades = new FastList<StandardEntity>();
* for(StandardEntity se : blockades) { new
* FastList<StandardEntity>(worldModel
* .getEntitiesOfType(StandardEntityURN.BLOCKADE); }
*
* potentialGoals.add(blockades);
*/
potentialGoals.add(new FastList<StandardEntity>(worldModel
.getEntitiesOfType(StandardEntityURN.BLOCKADE)));
// Compute closest goal, in order of lists
for (Collection<? extends StandardEntity> list : potentialGoals) {
for (StandardEntity se : list) {
// if (se instanceof Blockade) {
// if (!((Blockade) se).isPositionDefined()) {
// This happens when the position of a blockade is
// unknown (e.g., due to inconsistent updates)
// continue;
// }
// }
double distance = myPosition.distanceTo(new PositionXY(se
.getLocation(worldModel)));
if (distance < bestDistance) {
bestDistance = distance;
best = se;
}
}
if (best != null) {
return best;
}
}
return null;
}
/**
*
*/
public GoalContainer generateGoals() {
// Extract graph
SimpleGraph graph = freeRouting.getGraph();
WorldModelConverter converter = freeRouting.getConverter();
// Run complete Dijkstra
DijkstrasShortestPath dijkstra = new DijkstrasShortestPath(graph,
refugeSourceList, refugeCostList);
dijkstra.forceFullCompute();
GoalContainer goals = new GoalContainer();
List<StandardEntity> agents = new FastList<StandardEntity>();
agents.addAll(policeForces);
agents.addAll(otherAgents);
List<StandardEntity> agentsToClear = extractGoals(agents, dijkstra,
converter);
for (StandardEntity agent : agentsToClear) {
goals.addAgent((Human) agent);
}
List<StandardEntity> civiliansToClear = extractGoals(civilians,
dijkstra, converter);
for (StandardEntity civilian : civiliansToClear) {
goals.addCivilian((Civilian) civilian);
}
List<EntityID> unsearched = new FastList<EntityID>();
unsearched.addAll(worldModel.getUnknownBuildings());
unsearched.addAll(worldModel.getSafeUnsearchedBuildings());
for (EntityID entityID : unsearched) {
StandardEntity se = worldModel.getEntity(entityID);
if (needsClearing(se, dijkstra, converter)) {
goals.addUnsearchedBuilding((Building) se);
}
}
// TODO: Add burning buildings here
return goals;
}
private List<StandardEntity> extractGoals(
List<StandardEntity> potentialTargets,
DijkstrasShortestPath dijkstra, WorldModelConverter converter) {
List<StandardEntity> needClearing = new FastList<StandardEntity>();
for (StandardEntity standardEntity : potentialTargets) {
if (needsClearing(standardEntity, dijkstra, converter)) {
needClearing.add(standardEntity);
}
}
return needClearing;
}
private boolean needsClearing(StandardEntity poi,
DijkstrasShortestPath dijkstra, WorldModelConverter converter) {
StandardEntity position;
if (poi instanceof Human) {
Human human = (Human) poi;
if (!(human.isPositionDefined() && human.isHPDefined() && human
.getHP() > 0)) {
// Ignore if position undefined or dead
return false;
}
position = worldModel.getEntity(human.getPosition());
if (position instanceof Human) {
// Loaded on ambulance?
Human h = (Human) position;
if (h.isPositionDefined()) {
position = worldModel.getEntity(h.getPosition());
} else {
return false;
}
}
} else {
position = poi;
}
// Get position
WorldModelArea worldModelArea = converter.getWorldModelArea(position
.getID().getValue());
Set<Integer> simpleNeighbours = worldModelArea.getSimpleNeighbours();
// Need to check simple neighbours
boolean free = false;
for (int neighbour : simpleNeighbours) {
// Check if free
// System.out.println("Cost to " + neighbour + ": "
// + dijkstra.getCost(neighbour));
if (dijkstra.getCost(neighbour) < Double.POSITIVE_INFINITY) {
if (poi instanceof Human) {
SimpleGraphNode simpleGraphNode = converter
.getSimpleGraphNode(neighbour);
// Now check if possible to reach agent on node
PositionXY representativePoint = simpleGraphNode
.getRepresentativePoint();
double travelCost = freeRoutingCostFunction.getTravelCost(
(Area) position, representativePoint,
new PositionXY(poi.getLocation(worldModel)));
// System.out.println("Cost between " + representativePoint
// + " and "
// + new PositionXY(poi.getLocation(worldModel))
// + ": " + travelCost);
if (travelCost < Double.POSITIVE_INFINITY) {
free = true;
break;
}
} else {
free = true;
break;
}
}
} // Done checking
return !free;
}
/*
* (non-Javadoc)
*
* @see
* rescuecore2.worldmodel.WorldModelListener#entityAdded(rescuecore2.worldmodel
* .WorldModel, rescuecore2.worldmodel.Entity)
*/
@Override
public void entityAdded(WorldModel<? extends StandardEntity> model,
StandardEntity e) {
if (e instanceof Civilian) {
civilians.add(e);
Collections.sort(civilians, new EntityIDComparator());
}
}
/**
* @return the clearingModule
*/
public FutureClearingRoutingModule getClearingModule() {
return clearingModule;
}
@Override
public void entityRemoved(WorldModel<? extends StandardEntity> model,
StandardEntity e) {
// Shouldn't happen
}
}