package sample;
import static rescuecore2.misc.Handy.objectsToIDs;
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.ChangeSet;
import rescuecore2.messages.Command;
import rescuecore2.log.Logger;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.standard.entities.Building;
import rescuecore2.standard.entities.Refuge;
import rescuecore2.standard.entities.FireBrigade;
/**
A sample fire brigade agent.
*/
public class SampleFireBrigade extends AbstractSampleAgent<FireBrigade> {
private static final String MAX_WATER_KEY = "fire.tank.maximum";
private static final String MAX_DISTANCE_KEY = "fire.extinguish.max-distance";
private static final String MAX_POWER_KEY = "fire.extinguish.max-sum";
private int maxWater;
private int maxDistance;
private int maxPower;
@Override
public String toString() {
return "Sample fire brigade";
}
@Override
protected void postConnect() {
super.postConnect();
model.indexClass(StandardEntityURN.BUILDING, StandardEntityURN.REFUGE);
maxWater = config.getIntValue(MAX_WATER_KEY);
maxDistance = config.getIntValue(MAX_DISTANCE_KEY);
maxPower = config.getIntValue(MAX_POWER_KEY);
Logger.info("Sample fire brigade connected: max extinguish distance = " + maxDistance + ", max power = " + maxPower + ", max tank = " + maxWater);
}
@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);
}
FireBrigade me = me();
// Are we currently filling with water?
if (me.isWaterDefined() && me.getWater() < maxWater && location() instanceof Refuge) {
Logger.info("Filling with water at " + location());
sendRest(time);
return;
}
// Are we out of water?
if (me.isWaterDefined() && me.getWater() == 0) {
// Head for a refuge
List<EntityID> path = search.breadthFirstSearch(me().getPosition(), refugeIDs);
if (path != null) {
Logger.info("Moving to refuge");
sendMove(time, path);
return;
}
else {
Logger.debug("Couldn't plan a path to a refuge.");
path = randomWalk();
Logger.info("Moving randomly");
sendMove(time, path);
return;
}
}
// Find all buildings that are on fire
Collection<EntityID> all = getBurningBuildings();
// Can we extinguish any right now?
for (EntityID next : all) {
if (model.getDistance(getID(), next) <= maxDistance) {
Logger.info("Extinguishing " + next);
sendExtinguish(time, next, maxPower);
sendSpeak(time, 1, ("Extinguishing " + next).getBytes());
return;
}
}
// Plan a path to a fire
for (EntityID next : all) {
List<EntityID> path = planPathToFire(next);
if (path != null) {
Logger.info("Moving to target");
sendMove(time, path);
return;
}
}
List<EntityID> path = null;
Logger.debug("Couldn't plan a path to a fire.");
path = randomWalk();
Logger.info("Moving randomly");
sendMove(time, path);
}
@Override
protected EnumSet<StandardEntityURN> getRequestedEntityURNsEnum() {
return EnumSet.of(StandardEntityURN.FIRE_BRIGADE);
}
private Collection<EntityID> getBurningBuildings() {
Collection<StandardEntity> e = model.getEntitiesOfType(StandardEntityURN.BUILDING);
List<Building> result = new ArrayList<Building>();
for (StandardEntity next : e) {
if (next instanceof Building) {
Building b = (Building)next;
if (b.isOnFire()) {
result.add(b);
}
}
}
// Sort by distance
Collections.sort(result, new DistanceSorter(location(), model));
return objectsToIDs(result);
}
private List<EntityID> planPathToFire(EntityID target) {
// Try to get to anything within maxDistance of the target
Collection<StandardEntity> targets = model.getObjectsInRange(target, maxDistance);
if (targets.isEmpty()) {
return null;
}
return search.breadthFirstSearch(me().getPosition(), objectsToIDs(targets));
}
}