package iamrescue.agent.police;
import iamrescue.agent.AbstractIAMAgent;
import iamrescue.agent.police.goals.SimpleClearingGoal;
import iamrescue.execution.command.ClearCommand;
import iamrescue.execution.command.IPath;
import iamrescue.execution.command.MoveCommand;
import iamrescue.routing.IRoutingModule;
import iamrescue.routing.Path;
import iamrescue.routing.costs.SimpleDistanceRoutingCostFunction;
import iamrescue.routing.dijkstra.BidirectionalDijkstrasRoutingModule;
import iamrescue.routing.queries.QueryFactory;
import iamrescue.util.PositionXY;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javolution.util.FastList;
import org.apache.log4j.Logger;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.Point2D;
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;
public class SimpleIAMPoliceForce extends AbstractIAMAgent<PoliceForce> {
private static final String DISTANCE_KEY = "clear.repair.distance";
private static final Logger LOGGER = Logger
.getLogger(SimpleIAMPoliceForce.class);
private PoliceTaskModule taskModule;
private IRoutingModule clearRoutingModule;
private IPath lastPath = null;
private int distance;
/*
* (non-Javadoc)
*
* @see agent.AbstractIAMAgent#postConnect()
*/
@Override
protected void postConnect() {
super.postConnect();
LOGGER.debug("Postconnect");
distance = config.getIntValue(DISTANCE_KEY);
taskModule = new PoliceTaskModule(getWorldModel(), me().getID(),
getRoutingModule(), getTimer());
LOGGER.debug("task module done");
taskModule.initialise();
LOGGER.debug("Initialised");
clearRoutingModule = new BidirectionalDijkstrasRoutingModule(
getWorldModel(),
SimpleDistanceRoutingCostFunction.DEFAULT_NO_BLOCK_INSTANCE,
getTimer());
LOGGER.debug("CLearing done");
showWorldModelViewer();
}
@Override
protected void think(int time, ChangeSet changed) {
LOGGER.debug("Start update");
taskModule.update();
LOGGER.debug("End update");
LOGGER.debug("My task: " + taskModule.getMyCurrentGoal());
// Am I on a blocked road?
Area location = (Area) me().getPosition(getWorldModel());
Blockade block = getTargetBlockade(location, distance);
if (block != null) {
LOGGER.debug("Trying to clear");
ClearCommand clear = new ClearCommand();
clear.setBlockadeToClear(block);
getExecutionService().execute(clear);
return;
} else {
// Check if I can step towards a blockade
if (location.isBlockadesDefined()) {
List<EntityID> blockades = location.getBlockades();
for (EntityID entityID : blockades) {
MoveCommand move = new MoveCommand();
Blockade b = (Blockade) getWorldModel().getEntity(entityID);
if (b.getRepairCost() == 0) {
continue;
}
List<PositionXY> positions = new ArrayList<PositionXY>();
positions.add(new PositionXY(me().getLocation(
getWorldModel())));
positions
.add(new PositionXY(b.getLocation(getWorldModel())));
move.setPath(new Path(Collections.singletonList(location
.getID()), positions));
getExecutionService().execute(move);
LOGGER.debug("Moving to blockade " + b + " at "
+ b.getLocation(getWorldModel()));
return;
}
}
}
// Check next task
SimpleClearingGoal nextGoal = taskModule.getMyCurrentGoal();
if (nextGoal != null) {
Collection<EntityID> targets = new FastList<EntityID>();
// Plan clearing path to goal
if (nextGoal.getTarget().equals(me().getID())) {
for (StandardEntity se : getWorldModel().getEntitiesOfType(
StandardEntityURN.REFUGE)) {
targets.add(se.getID());
}
} else {
targets.add(nextGoal.getTarget());
}
IPath path = clearRoutingModule.findShortestPath(QueryFactory
.createQuery(getID(), targets));
if (path.isValid()) {
if (lastPath == null || !path.equals(lastPath)) {
lastPath = path;
MoveCommand moveCommand = new MoveCommand();
moveCommand.setPath(path);
getExecutionService().execute(moveCommand);
LOGGER.debug("Moving to goal " + nextGoal);
return;
}
} else {
LOGGER.warn("Invalid path produced by goal " + nextGoal);
}
}
LOGGER.debug("Searching");
doDefaultSearch();
/*
* Random r = new Random();
*
* // Walk randomly to a blocked road
*
* IPath path = null; while (path == null) { EntityID destination =
* null; List<Area> blocked = getBlockedAreas(); if (blocked.size() > 0)
* { destination = blocked.get(r.nextInt(blocked.size())).getID(); }
* else { blocked = getUnknownAreas(); if (blocked.size() > 0) {
* destination = blocked.get(r.nextInt(blocked.size())) .getID(); } else
* { // Random node short min =
* getWorldModel().getShortIndex().getMinID(); short max =
* getWorldModel().getShortIndex().getMaxID(); short shortID = (short)
* (min + (Math.random() * (max - min))); destination =
* getWorldModel().getEntity( getWorldModel().getShortIndex()
* .getEntityID(shortID)).getID(); } } LOGGER.debug("Random move from "
* + me() + " to " + getWorldModel().getEntity(destination));
*
* path = clearRoutingModule.findShortestPath(QueryFactory
* .createQuery(getID(), Collections.singleton(destination))); if
* (!path.isValid()) { path = null; } } MoveCommand moveCommand = new
* MoveCommand(); moveCommand.setPath(path);
* getExecutionService().execute(moveCommand);
* LOGGER.debug("Random move");
*/
}
private List<Area> getUnknownAreas() {
List<Area> areas = new ArrayList<Area>();
for (StandardEntity se : getWorldModel().getEntitiesOfType(
StandardEntityURN.ROAD)) {
Area area = (Area) se;
if (!area.isBlockadesDefined()) {
areas.add(area);
}
}
return areas;
}
private List<Area> getBlockedAreas() {
List<Area> areas = new ArrayList<Area>();
for (StandardEntity se : getWorldModel().getEntitiesOfType(
StandardEntityURN.ROAD)) {
Area area = (Area) se;
if (area.isBlockadesDefined() && area.getBlockades().size() > 0) {
areas.add(area);
}
}
for (StandardEntity se : getWorldModel().getEntitiesOfType(
StandardEntityURN.BUILDING)) {
Area area = (Area) se;
if (area.isBlockadesDefined() && area.getBlockades().size() > 0) {
areas.add(area);
}
}
return areas;
}
/*
* private Blockade getTargetBlockade() {
* Logger.debug("Looking for target blockade"); Area location = (Area)
* self().getPosition(getWorldModel());
* Logger.debug("Looking in current location"); Blockade result =
* getTargetBlockade(location, distance); if (result != null) { return
* result; } Logger.debug("Looking in neighbouring locations"); for
* (EntityID next : location.getNeighbours()) { location = (Area)
* model.getEntity(next); result = getTargetBlockade(location, distance); if
* ) (result != null) { return result; } } return null; }
*/
private Blockade getTargetBlockade(Area area, int maxDistance) {
LOGGER.debug("Looking for nearest blockade in " + area);
if (!area.isBlockadesDefined()) {
LOGGER.debug("Blockades undefined");
return null;
}
List<EntityID> ids = area.getBlockades();
// Find the first blockade that is in range.
PoliceForce self = (PoliceForce) me();
int x = self.getX();
int y = self.getY();
for (EntityID next : ids) {
Blockade b = (Blockade) model.getEntity(next);
if (b.isApexesDefined()) {
double d = findDistanceTo(b, x, y);
LOGGER.debug("Distance to " + b + " = " + d);
if (maxDistance < 0 || d < maxDistance) {
LOGGER.debug("In range");
return b;
}
}
}
LOGGER.debug("No blockades in range");
return null;
}
private int findDistanceTo(Blockade b, int x, int y) {
LOGGER.debug("Finding distance to " + b + " from " + x + ", " + y);
List<Line2D> lines = GeometryTools2D.pointsToLines(GeometryTools2D
.vertexArrayToPoints(b.getApexes()), true);
double best = Double.MAX_VALUE;
Point2D origin = new Point2D(x, y);
for (Line2D next : lines) {
Point2D closest = GeometryTools2D.getClosestPointOnSegment(next,
origin);
double d = GeometryTools2D.getDistance(origin, closest);
LOGGER.debug("Next line: " + next + ", closest point: " + closest
+ ", distance: " + d);
if (d < best) {
best = d;
LOGGER.debug("New best distance");
}
}
return (int) best;
}
protected List<StandardEntityURN> getAgentTypes() {
return Collections.singletonList(StandardEntityURN.POLICE_FORCE);
}
/* (non-Javadoc)
* @see iamrescue.agent.AbstractIAMAgent#fallback(int, rescuecore2.worldmodel.ChangeSet)
*/
@Override
protected void fallback(int time, ChangeSet changed) {
// TODO Auto-generated method stub
}
}