package iamrescue.agent.firebrigade; import iamrescue.agent.AbstractIAMAgent; import iamrescue.belief.IAMWorldModel; import iamrescue.belief.provenance.IProvenanceInformation; import iamrescue.belief.provenance.ProvenanceLogEntry; import iamrescue.execution.command.ExtinguishCommand; import iamrescue.execution.command.IPath; import iamrescue.execution.command.MoveCommand; import iamrescue.execution.command.RestCommand; import iamrescue.routing.Path; import iamrescue.routing.queries.IRoutingLocation; import iamrescue.routing.queries.RoutingLocation; import iamrescue.routing.queries.RoutingQuery; 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.HashSet; import java.util.List; import java.util.Set; import javolution.util.FastSet; 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.Building; import rescuecore2.standard.entities.FireBrigade; import rescuecore2.standard.entities.Human; import rescuecore2.standard.entities.StandardEntity; import rescuecore2.standard.entities.StandardEntityURN; import rescuecore2.standard.entities.StandardPropertyURN; import rescuecore2.worldmodel.ChangeSet; import rescuecore2.worldmodel.EntityID; // This is IAMFireBrigadeTest public class IAMStrategyFireBrigade extends AbstractIAMAgent<FireBrigade> { private final double STICK_EXTINGUISH_MULTIPLIER = 2; // private FirePredictor firePredictor = null; private FastFirePredictor firePredictor = null; // set this to 1 to switch off sticking behaviour. Prevents thrashing private final int STICK_TO_CLOSE_FIRES_TIME = 2000; private int lastSiteChangeTime = Integer.MIN_VALUE; // private int STICK_TO_DISTANCE = MAX_DISTANCE; private final int TIMESTEPS_INTO_THE_FUTURE = 5;// try increase it private int MAX_WATER = 15000; // checked private int MAX_DISTANCE = 60000; // checked private int ALMOST_MAX_DISTANCE = (int) (0.7 * MAX_DISTANCE); private int viewDistance = 30000; // from // iamrescue/belief/BuildingSearchUtility.java private static final Logger LOGGER = Logger .getLogger(IAMStrategyFireBrigade.class); private static final int ALWAYS_VIEW_TIME_THRESHOLD = 2; private HeatTransferGraph heatTransferGraph; private ISpeedInfo speed; private final boolean DEBUG_FIRE = false; // private static ArrayList<IAMStrategyFireBrigade> agents = new // ArrayList<IAMStrategyFireBrigade>(); private ArrayList<FireBrigade> fireBrigades; private int timestepsSinceCurrentTargetObserved = 0; private FireStrategy strategy = null; // private ArrayList<ArrayList<Building>> fireSite = null; // private ArrayList<ArrayList<Building>> centreOfFireSite = new // ArrayList<ArrayList<Building>>(); private final int TimeAtTargetPerStep = 2; private FireStrategyState strategyState = new FireStrategyState( TimeAtTargetPerStep); private Building lastTargetAllocated; private VisibilityMap visibilityMap; @Override protected void postConnect() { super.postConnect(); this.MAX_WATER = config.getIntValue("fire.tank.maximum"); this.MAX_DISTANCE = config.getIntValue("fire.extinguish.max-distance"); this.viewDistance = config.getIntValue("perception.los.max-distance", 30000); // pathPlanner = this.getRoutingModule(); IAMWorldModel world = getWorldModel(); // firePredictor = new FirePredictor(world); firePredictor = new FastFirePredictor(this.getTimer(), world, me() .getID()); heatTransferGraph = firePredictor.getHeatTransferGraph(); // initialise fireBrigades fireBrigades = new ArrayList<FireBrigade>(); // we get all the firebrigades IDs Collection<StandardEntity> allFireBrigades = world .getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE); for (StandardEntity standardEntity : allFireBrigades) fireBrigades.add((FireBrigade) standardEntity); Collections.sort(fireBrigades, EntityIDComparator.DEFAULT_INSTANCE); // showWorldModelViewer(); strategy = new FireStrategy(getFireBrigades(), getRoutingModule(), this .getID(), this); // Collection<StandardEntity> entitiesOfType = // getWorldModel().getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE); // List<StandardEntity> entities = new // ArrayList<StandardEntity>(entitiesOfType); // Collections.sort(entities,EntityIDComparator.DEFAULT_INSTANCE); // if(entities.get(0).equals(me())) { // showFireImportanceModel(firePredictor); // } // System.gc() visibilityMap = new VisibilityMap(world, viewDistance); } protected List<FireBrigade> getFireBrigades() { return fireBrigades; } @Override protected void think(int time, ChangeSet changed) { // firePredictor.updateImportanceModel(); mainThink(time, changed); /*int halfSize = (fireBrigades.size() + 1) / 2; int restDivision = getTimer().getTime() % halfSize; if (me().getID().equals(fireBrigades.get(restDivision).getID())) { if (LOGGER.isDebugEnabled()) { LOGGER.debug(me().getID().getValue() + "am updating"); } firePredictor.updateImportanceModel(); } else if (restDivision + halfSize < fireBrigades.size()) { if (me().getID().equals( fireBrigades.get(restDivision + halfSize).getID())) { if (LOGGER.isDebugEnabled()) { LOGGER.debug(me().getID().getValue() + "am updating"); } firePredictor.updateImportanceModel(); } }*/ } protected void mainThink(int time, ChangeSet changed) { stopIfInterrupted(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Start of think at timestep " + time + " for: " + this.toString()); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("CurrentTarget is: " + (currentTarget == null ? "null" : currentTarget.getID() .getValue())); } String location = this.getLocation().getURN(); if (location.equals(StandardEntityURN.REFUGE.toString())) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("We are at the refuge."); } if (this.me().getWater() < MAX_WATER) { // send rest command, and we will fill with water. getExecutionService().execute(new RestCommand()); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Filling with water, ending turn."); } return; } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Will not get more water."); } } if (this.me().getWater() == 0) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("No water, going to refuge to fill up."); } Collection<StandardEntity> refuges = getWorldModel() .getEntitiesOfType(StandardEntityURN.REFUGE); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Going to closest of refuges: " + refuges); } IPath path = getRoutingModule().findShortestPath(me(), refuges); // if the full path is valid and it's a refuge, then go fully in if (path.isValid()) { if (LOGGER.isDebugEnabled()) { LOGGER .debug("Sending full path, since we want to go into the refuge, path is: " + path.toString()); } this.sendMove(path); return; } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Could not travel to refuges."); } doDefaultSearch(); return; } } speed = this.getSpeedInfo(); /* * State machine */ boolean newTarget = false; boolean extinguish = false; // check if we are within range int distanceToTarget = Integer.MAX_VALUE; if (currentTarget != null) { distanceToTarget = getWorldModel().getDistance(me().getID(), currentTarget.getID()); } switch (strategyState.getAgentState()) { case FREE: default: newTarget = true; break; case TRAVELLING: newTarget = true; break;/* if (distanceToTarget < MAX_DISTANCE) { // System.out.println("We are close enough"); // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("We are close enough"); extinguish = true; break; } else { if (LOGGER.isDebugEnabled()) { LOGGER .debug("Target is out of range, moving closer. Distance = " + distanceToTarget + " > " + MAX_DISTANCE); } if (goToBuilding(currentTarget)) { // if path is valid, then command was sent, so return if (LOGGER.isDebugEnabled()) { LOGGER.debug("Going to building " + currentTarget.getID() + ", and ending turn."); } return; } else { if (LOGGER.isDebugEnabled()) { LOGGER .debug("Unable to go to current Target, getting a new target."); } newTarget = true; break; } }*/ case EXTINGUISHING: // System.out.println("Calculated distance between us and target: "+distanceToTarget); // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Calculated distance between us and target: "+distanceToTarget); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Distance to building is: " + distanceToTarget); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Viewing distance is: " + viewDistance); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Extinguish distance is: " + MAX_DISTANCE); } int lastObserved = getTimeLastObserved(currentTarget); // boolean knowStatus = (lastObserved == getTimer().getTime()); /* * if (knowStatus) { if (LOGGER.isDebugEnabled()) { * LOGGER.debug("Current target has been observed this timestep."); * } timestepsSinceCurrentTargetObserved = 0; } else { if * (LOGGER.isDebugEnabled()) { LOGGER.debug( * "Current target hasn't changed this timestep, incrementing time since changed." * ); } timestepsSinceCurrentTargetObserved++; } */ // int allowedRange = 0; // final int maxTimeStepsWithoutSeeingTarget = 4; // final int maxTimeStepsWithoutSeeingTarget = 4; // if we haven't seen an update to our target in over 4 // timesteps... // boolean needToSee; /* * if (getTimer().getTime() - lastObserved >= * ALWAYS_VIEW_TIME_THRESHOLD) { // building data not changed * recently, so go closer to // update our model if * (LOGGER.isDebugEnabled()) { LOGGER.debug( * "current Target not updated recently, going closer to update model. (ext)" * ); } needToSee = true; } else { // building has been changed * recently, so only make sure we // are in the extinguishing range * if (LOGGER.isDebugEnabled()) { LOGGER * .debug("current Target updated recently, will keep distance. (ext)" * ); } needToSee = false; } */ if (getTimer().getTime() - lastObserved < ALWAYS_VIEW_TIME_THRESHOLD) { boolean noLongerOnFire = (lastObserved == getTimer().getTime()) && currentTarget.isFierynessDefined() && (currentTarget.getFieryness() > 3); boolean allocationTimeOut = strategyState.addTimeAtTarget() >= strategyState .getTimePerTarget(); // We must be at target to be at this state. if (noLongerOnFire || allocationTimeOut) { // we've done enough strategyState.resetTimePerTarget(); newTarget = true; break; } else { // still extinguish extinguish = true; break; } } else { if (LOGGER.isDebugEnabled()) { LOGGER .debug("Target is out of range, moving closer. (ext)"); } if (goToBuilding(currentTarget, true)) { // if path is valid, then command was sent, so return if (LOGGER.isDebugEnabled()) { LOGGER.debug("Going to building " + currentTarget.getID() + ", and ending turn. (ext)"); } return; } else { if (LOGGER.isDebugEnabled()) { LOGGER .debug("Unable to go to current Target, getting a new target. (ext)"); } newTarget = true; break; } } } if (strategy.needToReassign()) { newTarget = true; } // newTarget = true; if (newTarget) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("newTarget"); } boolean goingToTarget = false; EntityID lastTarget = null; int counter = 0; final int MAX_COUNTER = 20; // Seb's Comment: I don't know why we need a loop here. I think it // will run without -- if safe, we should remove this. while (!goingToTarget && counter < MAX_COUNTER) { counter++; stopIfInterrupted(); try { ArrayList<Building> fringeBuildings = new ArrayList<Building>(); ArrayList<Building> centreBuildings = new ArrayList<Building>(); for (FastFireSite fireSite : firePredictor.getFireSites()) { stopIfInterrupted(); fringeBuildings.addAll(fireSite.getFringe()); centreBuildings.addAll(fireSite.getCenter()); } currentTarget = getTarget(fringeBuildings, centreBuildings); } catch (Exception e) { LOGGER.error("Exception from strategy: " + e.toString()); e.printStackTrace(); } if (currentTarget == null) { if (LOGGER.isDebugEnabled()) { LOGGER .debug("strategy gave up a null target, do default search."); } // getExecutionService().execute(new RestCommand()); doDefaultSearch(); strategyState .setState(iamrescue.agent.firebrigade.FireStrategyState.AgentState.FREE); return; } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("trying to go to target: " + currentTarget.getID() + " from our location: " + me().getPosition()); } distanceToTarget = getWorldModel().getDistance( me().getID(), currentTarget.getID()); // update // in case currentTarget changed boolean observedRecently = (getTimer().getTime() - getTimeLastObserved(currentTarget) < ALWAYS_VIEW_TIME_THRESHOLD); if (distanceToTarget < MAX_DISTANCE && observedRecently) { extinguish = true; goingToTarget = true; // don't return, extinguish } else { if (LOGGER.isDebugEnabled()) { LOGGER .debug("Thought I was extinguishing, but too far."); } strategyState .setState(iamrescue.agent.firebrigade.FireStrategyState.AgentState.TRAVELLING); goingToTarget = goToBuilding(currentTarget, !observedRecently); if (goingToTarget) { return; } else { // go around and get a new target. if (lastTarget == currentTarget.getID()) { // we're tried to get this target before, so // we've looped around all possibles, so // just do default search for now. if (LOGGER.isDebugEnabled()) { LOGGER .debug("strategy gave us no targets we can go to, so do default search."); } doDefaultSearch(); strategyState .setState(iamrescue.agent.firebrigade.FireStrategyState.AgentState.FREE); return; } else { lastTarget = currentTarget.getID(); } } } } } if (counter >= MAX_COUNTER) { LOGGER .error("Reached maximum number of iterations. Defaulting to search"); doDefaultSearch(); strategyState .setState(iamrescue.agent.firebrigade.FireStrategyState.AgentState.FREE); return; } } if (extinguish) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("extinguish"); } ExtinguishCommand extinguishCommand = new ExtinguishCommand(); extinguishCommand.setBuildingToExtinguish(currentTarget); extinguishCommand.setPercentageOfFullPower(1.0); stopIfInterrupted(); getExecutionService().execute(extinguishCommand); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Extinguishing target " + currentTarget.getID() + ", and ending turn."); } strategyState .setState(iamrescue.agent.firebrigade.FireStrategyState.AgentState.EXTINGUISHING); return; } stopIfInterrupted(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Ending turn by searching."); } doDefaultSearch(); return; } private int getTimeLastObserved(Building b) { IProvenanceInformation provenance = getWorldModel().getProvenance( b.getID(), StandardPropertyURN.FIERYNESS); if (provenance == null) { return -100; } ProvenanceLogEntry lastDefined = provenance.getLastDefined(); if (lastDefined == null) { return -100; } return lastDefined.getTimeStep(); } private Building getTarget(ArrayList<Building> fringeBuildings, ArrayList<Building> centreBuildings) { List<Building> orderedBuildingsIncreasingImportance = new ArrayList<Building>(); if (lastSiteChangeTime + STICK_TO_CLOSE_FIRES_TIME <= getTimer() .getTime()) { // Consider all sites lastSiteChangeTime = getTimer().getTime(); orderedBuildingsIncreasingImportance.addAll(firePredictor .getOrderOfImportantBuildingsToExtinguish(centreBuildings)); List<Building> fieryness1buildings = new ArrayList<Building>(); List<Building> fieryness2buildings = new ArrayList<Building>(); for (Building building : fringeBuildings) { if (building.getFieryness() == 1) { fieryness1buildings.add(building); } else { fieryness2buildings.add(building); } } orderedBuildingsIncreasingImportance .addAll(firePredictor .getOrderOfImportantBuildingsToExtinguish(fieryness2buildings)); orderedBuildingsIncreasingImportance .addAll(firePredictor .getOrderOfImportantBuildingsToExtinguish(fieryness1buildings)); } else { // Consider only local targets List<Building> closeFringe1 = new ArrayList<Building>(); List<Building> closeFringe2 = new ArrayList<Building>(); List<Building> closeCentre = new ArrayList<Building>(); List<Building> farFringe1 = new ArrayList<Building>(); List<Building> farFringe2 = new ArrayList<Building>(); List<Building> farCentre = new ArrayList<Building>(); List<Building> orderedFringe = firePredictor .getOrderOfImportantBuildingsToExtinguish(fringeBuildings); List<Building> orderedCentre = firePredictor .getOrderOfImportantBuildingsToExtinguish(centreBuildings); PositionXY myPosition = new PositionXY(me().getLocation( getWorldModel())); for (int i = 0; i < orderedFringe.size(); i++) { Building building = orderedFringe.get(i); PositionXY buildingLocation = new PositionXY(building .getLocation(getWorldModel())); if (myPosition.distanceTo(buildingLocation) <= MAX_DISTANCE * STICK_EXTINGUISH_MULTIPLIER) { if (building.getFieryness() == 1) { closeFringe1.add(building); } else { closeFringe2.add(building); } } else { if (building.getFieryness() == 1) { farFringe1.add(building); } else { farFringe2.add(building); } } } for (int i = 0; i < orderedCentre.size(); i++) { Building building = orderedCentre.get(i); PositionXY buildingLocation = new PositionXY(building .getLocation(getWorldModel())); if (myPosition.distanceTo(buildingLocation) <= MAX_DISTANCE * STICK_EXTINGUISH_MULTIPLIER) { closeCentre.add(building); } else { farCentre.add(building); } } orderedBuildingsIncreasingImportance.addAll(farCentre); orderedBuildingsIncreasingImportance.addAll(farFringe2); orderedBuildingsIncreasingImportance.addAll(farFringe1); orderedBuildingsIncreasingImportance.addAll(closeCentre); orderedBuildingsIncreasingImportance.addAll(closeFringe2); orderedBuildingsIncreasingImportance.addAll(closeFringe1); } if (orderedBuildingsIncreasingImportance.size() == 0) { return null; } else { int i = orderedBuildingsIncreasingImportance.size() - 1; Building b = orderedBuildingsIncreasingImportance.get(i); int timeLastObserved = getTimeLastObserved(b); boolean goToViewDistance = (getTimer().getTime() - timeLastObserved >= ALWAYS_VIEW_TIME_THRESHOLD); IPath path = getExtinguishPath(b, goToViewDistance); /* * getReusableRouting().findShortestPath(me(), * orderedBuildings.get(i)); */ while (!path.isValid() && i > 0) { i--; b = orderedBuildingsIncreasingImportance.get(i); timeLastObserved = getTimeLastObserved(b); goToViewDistance = (getTimer().getTime() - timeLastObserved >= ALWAYS_VIEW_TIME_THRESHOLD); path = getExtinguishPath(b, goToViewDistance); } if (path.isValid()) { return orderedBuildingsIncreasingImportance.get(i); } else { return null; } } } private boolean areWeAtNeighbour(Collection<Building> buildingIDs) { for (Building id : buildingIDs) { for (EntityID neighbourID : id.getNeighbours()) { if (neighbourID.getValue() == me().getPosition().getValue()) { return true; } } } return false; } private boolean goToBuilding(Building location) { return goToBuilding(location, false); } private boolean goToBuilding(Building location, boolean alsoNeedToSee) { IPath path = getExtinguishPath(location, alsoNeedToSee); if (path.isValid() && path.getLocations().size() > 1) { sendMove(path); return true; } else { LOGGER.debug("Suggested path: " + path); return false; } } private boolean goToBuildingOld(Building locations) { // full path into the building IPath path = getRoutingModule().findShortestPath(me(), locations); // get the shortest possible path that we can still extinguish from IPath shortPath = removeLastPathNode(path, Collections .singleton(locations)); if (shortPath.isValid()) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Sending shorter path: " + shortPath.toString()); } this.sendMove(shortPath); return true; } else { if (path.isValid()) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Sending longer path: " + path.toString()); } this.sendMove(path); return true; } } if (LOGGER.isDebugEnabled()) { LOGGER.debug("No paths found in goToBuilding."); } return false; } protected void sendMove(IPath path) { MoveCommand move = new MoveCommand(); move.setPath(path); stopIfInterrupted(); this.getExecutionService().execute(move); } protected void sendMove(List<PositionXY> path) { MoveCommand move = new MoveCommand(); move.setPath(new Path(Collections.singletonList(me().getPosition( getWorldModel()).getID()), path)); stopIfInterrupted(); this.getExecutionService().execute(move); } Building currentTarget = null; protected IPath removeLastPathNode(IPath path, Collection<Building> locations) { IPath lastValidPath = path; List<EntityID> nodes = null; if (path.isValid()) { lastValidPath = path; } else { // path isn't valid, so we have to try to go to any of the // destinations neighbours List<EntityID> neighbours = new ArrayList<EntityID>(); for (StandardEntity destination : locations) { neighbours.addAll(((Area) destination).getNeighbours()); } if (neighbours.size() == 0) { return path; // the Invalid_Path } IPath newPath = getRoutingModule().findShortestPath(getID(), neighbours); if (newPath.isValid()) { nodes = newPath.getLocations(); lastValidPath = newPath; } else { return path; // the Invalid_Path } } nodes = lastValidPath.getLocations(); // if path has less than two nodes, don't change it if (nodes.size() < 2) { return path; } // move back 1 node, or move more if we can still extinguish // int moveBack = 2; EntityID target = nodes.get(nodes.size() - 1); IPath newpath = path; path = path.removeLastNode(); int distance = Integer.MAX_VALUE; if (path.isValid()) { distance = getWorldModel().getDistance( path.getLocations().get(path.getLocations().size() - 1), target); } while (distance < MAX_DISTANCE && path.isValid()) { newpath = path; path = path.removeLastNode(); if (path.isValid()) { distance = getWorldModel() .getDistance( path.getLocations().get( path.getLocations().size() - 1), target); } } return newpath; } public StandardEntity getLocation() { return ((Human) me()).getPosition(getWorldModel()); } // public FirePredictor getFirePredictor() { // return firePredictor; // } public FastFirePredictor getFirePredictor() { return firePredictor; } // protected boolean newTarget() { // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("newTarget"); // } // // // gets the 1 building with the highest context importance // List<Building> importantBuilding = // firePredictor.getBuildingsToExtinguish(10, TIMESTEPS_INTO_THE_FUTURE); // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Important buildings list is: " // + importantBuilding.toString()); // } // for (Building modelBuilding : importantBuilding) { // Building newB = (Building) getWorldModel().getEntity( // modelBuilding.getID()); // // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Planning to travel to: " // + newB.getID().getValue()); // } // // if (!isBurntOut(newB) && this.isValidTarget(newB)) { // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Building is a valid target."); // } // if (goToBuilding(newB)) { // // if path is valid, then command was sent, so return // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Going to building " + newB.getID()); // } // currentTarget = newB; // timestepsSinceCurrentTargetChanged = 0; // return true; // } else { // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Go to building failed."); // } // } // } // } // // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Checking for buildings that might be on fire."); // } // HashSet<Building> maybeOnFire = this.getBuildingsThatMightBeOnFire(this // .getWorldModel()); // for (Building b : maybeOnFire) { // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Checking building " + b.getID().getValue()); // } // if (goToBuilding(b)) { // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Going to building " + b.getID().getValue()); // } // currentTarget = b; // return true; // } else { // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Couldn't go to building."); // } // } // } // // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("newTarget returning false."); // } // return false; // } public HashSet<Building> getBuildingsThatMightBeOnFire(IAMWorldModel wm) { HashSet<Building> mightBeOnFire = new HashSet<Building>(); for (StandardEntity e : wm .getEntitiesOfType(StandardEntityURN.BUILDING)) { Building b = (Building) e; if (!isBurntOut(b)) { mightBeOnFire.add(b); } } return mightBeOnFire; } // protected boolean changeTarget() { // // if (currentTarget == null) { // // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("Current target is null, so will change."); // } // return newTarget(); // } // // /** // * what happens with predicted buildings??? // */ // // building is not on fire, so change (or burned out) // Building b = (Building) getWorldModel() // .getEntity(currentTarget.getID()); // // if (this.getBuildingsThatMightBeOnFire(getWorldModel()).contains(b)) { // if (LOGGER.isDebugEnabled()) { // LOGGER // .debug("Building is in list of those that might be on fire..."); // } // // if (this.isValidTarget(b) && !isBurntOut(b)) { // if (LOGGER.isDebugEnabled()) { // LOGGER // .debug("...and it is on fire, so don't change target."); // } // return false; // } else { // // TODO check if there are buildings on fire, if so, change // // target // List<Building> importantBuilding = firePredictor // .getBuildingsToExtinguish(10, TIMESTEPS_INTO_THE_FUTURE); // if (importantBuilding.size() > 0) { // if (LOGGER.isDebugEnabled()) { // LOGGER // .debug("...but there are some on fire, so we will change target."); // } // return newTarget(); // } else { // if (LOGGER.isDebugEnabled()) { // LOGGER // .debug("...and there are none on fire, so we will search."); // } // currentTarget = null; // doDefaultSearch(); // return true; // } // } // } else if (!this.isValidTarget(b)) { // if (LOGGER.isDebugEnabled()) { // LOGGER // .debug("Current target is not a valid target, so changing."); // } // return newTarget(); // } // // if (LOGGER.isDebugEnabled()) { // LOGGER.debug("changeTarget returning false."); // } // return false; // } public int getWater() { return this.me().getWater(); } public String toString() { return "IAMFireBrigade " + this.getID() + ", water:" + getWater() + ", location:" + getLocation().getID().getValue(); } List<FireSite> allFireSites = new ArrayList<FireSite>(); public boolean isValidTarget(Building b) { if (b == null) { // System.out.println("FIRE MODEL: isValidTarget failed b = null"); return false; } if (b.getFierynessProperty().getValue() != null && (b.getFieryness() == 8 || b.getFieryness() == 4 || b.getFieryness() == 5 || b.getFieryness() == 6 || b .getFieryness() == 7)) { // System.out.println("FIRE MODEL: isValidTarget failed fieryness = 4-8"); return false; } if (!b.isOnFire()) { // System.out.println("FIRE MODEL: isValidTarget failed b is not on fire (1)"); return false; } if (b.isOnFire() && b.getIgnitionProperty().getValue() != null && b.getFieryness() == 8) { // System.out.println("FIRE MODEL: isValidTarget failed b is not on fire (fieryness == 8)"); return false; } // if getignition is not undefined and is set to false if (b.getIgnitionProperty().getValue() != null && !b.getIgnition()) { // System.out.println("FIRE MODEL: isValidTarget failed not ignited"); return false; } // System.out.println("FIRE MODEL: isValidTarget passed"); return true; } // @Override // protected StandardEntityURN getAgentType() { // return StandardEntityURN.FIRE_BRIGADE; // } private IPath getExtinguishPath(Building building, boolean alsoWithinViewDistance) { int distance = (alsoWithinViewDistance) ? (int) Math.min( ALMOST_MAX_DISTANCE, 0.9 * viewDistance) : ALMOST_MAX_DISTANCE; Collection<StandardEntity> possibleExtinguishPositions = getWorldModel() .getObjectsInRange(building, distance); PositionXY buildingPosition = new PositionXY(building .getLocation(getWorldModel())); // LOGGER.debug("Checking " + building); List<StandardEntity> extinguishPositions = new ArrayList<StandardEntity>(); List<IRoutingLocation> destinations = new ArrayList<IRoutingLocation>(); // IRoutingLocation destination= new RoutingLocation(id, position) for (StandardEntity area : possibleExtinguishPositions) { // LOGGER.debug("Evaluating " + area); if (area instanceof Area && !area.equals(building)) { if (area instanceof Building) { Building b = (Building) area; if (b.isFierynessDefined() && b.getFieryness() >= 1 && b.getFieryness() <= 3) { // Ignore buildings on fire continue; } } if (alsoWithinViewDistance && area instanceof Building) { continue; } PositionXY locationXY = new PositionXY(((Area) area).getX(), ((Area) area).getY()); if (locationXY.distanceTo(buildingPosition) < distance) { if (alsoWithinViewDistance) { Set<EntityID> roadsToExtinguishFrom = visibilityMap .getRoadsToExtinguishFrom(building.getID()); if (roadsToExtinguishFrom != null && roadsToExtinguishFrom.contains(area.getID())) { extinguishPositions.add(area); destinations.add(new RoutingLocation(area.getID(), locationXY)); } } else { extinguishPositions.add(area); destinations.add(new RoutingLocation(area.getID(), locationXY)); } } } } RoutingQuery query = new RoutingQuery( new RoutingLocation(me().getID()), destinations); return getReusableRouting().findShortestPath(query); } private Collection<Line2D> getBlockingLines( Collection<StandardEntity> potentialInRange, Building toIgnore) { // SpatialQuery query = SpatialQueryFactory.queryWithinDistance( // new PositionXY(location), viewDistance, Building.class); // Collection<StandardEntity> inRange = spatialIndex.query(query); Collection<Line2D> result = new FastSet<Line2D>(); for (StandardEntity se : potentialInRange) { if (se instanceof Building && !se.equals(toIgnore)) { int[] apexes = ((Building) se).getApexList(); List<Point2D> points = GeometryTools2D .vertexArrayToPoints(apexes); List<Line2D> lines = GeometryTools2D .pointsToLines(points, true); result.addAll(lines); } } return result; } private void debug(String message) { if (LOGGER.isDebugEnabled() || DEBUG_FIRE) { LOGGER.debug(message); // System.out.println(Calendar.getInstance().getTime().toString()+ // " IAMFireBrigade ["+this.getID()+"] " +message); } } @Override protected void fallback(int time, ChangeSet changed) { // TODO move to closest fire, or if in range of one, extinguish it. Building closestFireBuilding = null; int closestFireBuildingDistance = Integer.MAX_VALUE; for (StandardEntity entity : this.getWorldModel() .getEntitiesOfType(StandardEntityURN.BUILDING, StandardEntityURN.AMBULANCE_CENTRE, StandardEntityURN.POLICE_OFFICE, StandardEntityURN.FIRE_STATION)) { Building building = (Building) entity; if (this.isValidTarget(building)) { // this building is on fire int distance = getWorldModel().getDistance(me().getID(), building.getID()); if (distance < this.MAX_DISTANCE) { // within range, so extinguish ExtinguishCommand extinguishCommand = new ExtinguishCommand(); extinguishCommand.setBuildingToExtinguish(building); extinguishCommand.setPercentageOfFullPower(1.0); stopIfInterrupted(); getExecutionService().execute(extinguishCommand); return; } else { if (distance < closestFireBuildingDistance) { closestFireBuildingDistance = distance; closestFireBuilding = building; } } } } if (closestFireBuilding == null) { doDefaultSearch(); } else { goToBuilding(closestFireBuilding); } return; } public boolean isBurntOut(Building b) { if (b.isFierynessDefined()) { if (b.getFieryness() == 8) { return true; } } return false; } public boolean isOnFire(Building b) { if (b.isFierynessDefined()) { if (b.getFieryness() >= 1 && b.getFieryness() <= 3) { return true; } } return false; } @Override protected List<StandardEntityURN> getAgentTypes() { return Collections.singletonList(StandardEntityURN.FIRE_BRIGADE); } }