package sample;
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.ChangeSet;
import rescuecore2.messages.Command;
import rescuecore2.log.Logger;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.standard.entities.Road;
import rescuecore2.standard.entities.Blockade;
import rescuecore2.standard.entities.PoliceForce;
import rescuecore2.standard.entities.Area;
/**
A sample police force agent.
*/
public class SamplePoliceForce extends AbstractSampleAgent<PoliceForce> {
private static final String DISTANCE_KEY = "clear.repair.distance";
private int distance;
@Override
public String toString() {
return "Sample police force";
}
@Override
protected void postConnect() {
super.postConnect();
model.indexClass(StandardEntityURN.ROAD);
distance = config.getIntValue(DISTANCE_KEY);
}
@Override
protected void think(int time, ChangeSet changed, Collection<Command> heard) {
if (time == config.getIntValue(kernel.KernelConstants.IGNORE_AGENT_COMMANDS_KEY)) {
// Subscribe to channel 1
sendSubscribe(time, 1);
}
for (Command next : heard) {
Logger.debug("Heard " + next);
}
// Am I near a blockade?
Blockade target = getTargetBlockade();
if (target != null) {
Logger.info("Clearing blockade " + target);
sendSpeak(time, 1, ("Clearing " + target).getBytes());
sendClear(time, target.getID());
return;
}
// Plan a path to a blocked area
List<EntityID> path = search.breadthFirstSearch(me().getPosition(), getBlockedRoads());
if (path != null) {
Logger.info("Moving to target");
Road r = (Road)model.getEntity(path.get(path.size() - 1));
Blockade b = getTargetBlockade(r, -1);
sendMove(time, path, b.getX(), b.getY());
Logger.debug("Path: " + path);
Logger.debug("Target coordinates: " + b.getX() + ", " + b.getY());
return;
}
Logger.debug("Couldn't plan a path to a blocked road");
Logger.info("Moving randomly");
sendMove(time, randomWalk());
}
@Override
protected EnumSet<StandardEntityURN> getRequestedEntityURNsEnum() {
return EnumSet.of(StandardEntityURN.POLICE_FORCE);
}
private List<EntityID> getBlockedRoads() {
Collection<StandardEntity> e = model.getEntitiesOfType(StandardEntityURN.ROAD);
List<EntityID> result = new ArrayList<EntityID>();
for (StandardEntity next : e) {
Road r = (Road)next;
if (r.isBlockadesDefined() && !r.getBlockades().isEmpty()) {
result.add(r.getID());
}
}
return result;
}
private Blockade getTargetBlockade() {
Logger.debug("Looking for target blockade");
Area location = (Area)location();
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 == null || !area.isBlockadesDefined()) {
// Logger.debug("Blockades undefined");
return null;
}
List<EntityID> ids = area.getBlockades();
// Find the first blockade that is in range.
int x = me().getX();
int y = me().getY();
for (EntityID next : ids) {
Blockade b = (Blockade)model.getEntity(next);
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;
}
/**
Get the blockade that is nearest this agent.
@return The EntityID of the nearest blockade, or null if there are no blockades in the agents current location.
*/
/*
public EntityID getNearestBlockade() {
return getNearestBlockade((Area)location(), me().getX(), me().getY());
}
*/
/**
Get the blockade that is nearest a point.
@param area The area to check.
@param x The X coordinate to look up.
@param y The X coordinate to look up.
@return The EntityID of the nearest blockade, or null if there are no blockades in this area.
*/
/*
public EntityID getNearestBlockade(Area area, int x, int y) {
double bestDistance = 0;
EntityID best = null;
Logger.debug("Finding nearest blockade");
if (area.isBlockadesDefined()) {
for (EntityID blockadeID : area.getBlockades()) {
Logger.debug("Checking " + blockadeID);
StandardEntity entity = model.getEntity(blockadeID);
Logger.debug("Found " + entity);
if (entity == null) {
continue;
}
Pair<Integer, Integer> location = entity.getLocation(model);
Logger.debug("Location: " + location);
if (location == null) {
continue;
}
double dx = location.first() - x;
double dy = location.second() - y;
double distance = Math.hypot(dx, dy);
if (best == null || distance < bestDistance) {
bestDistance = distance;
best = entity.getID();
}
}
}
Logger.debug("Nearest blockade: " + best);
return best;
}
*/
}