/** * */ package iamrescue.agent.search; import iamrescue.agent.AbstractIAMAgent; import iamrescue.belief.IAMWorldModel; import iamrescue.communication.messages.AgentStuckMessage; import iamrescue.communication.messages.MessagePriority; import iamrescue.communication.scenario.IAMCommunicationModule; import iamrescue.execution.IExecutionService; import iamrescue.execution.command.IPath; import iamrescue.execution.command.MoveCommand; import iamrescue.execution.command.RandomMoveCommand; import iamrescue.routing.IRoutingModule; import iamrescue.routing.Path; import iamrescue.util.PositionXY; import iamrescue.util.comparators.RoadComparator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import javolution.util.FastList; import javolution.util.FastSet; import org.apache.log4j.Logger; import rescuecore2.config.Config; import rescuecore2.standard.entities.Area; import rescuecore2.standard.entities.Human; import rescuecore2.standard.entities.Road; import rescuecore2.standard.entities.StandardEntity; import rescuecore2.standard.entities.StandardEntityURN; import rescuecore2.worldmodel.EntityID; /** * @author Simon Coordinated search behaviour * * Agents search a subset of locations - defined at the start as a * shared randomisation of the map * * id dictates which section of the list to favour * * they only do this when they detect another agent - more commenly they * search closest * */ public class ClashRandomisedClosestSearchBehaviour implements ISearchBehaviour { private EntityID myself; private IAMWorldModel worldModel; private IExecutionService executionService; private IRoutingModule routingModule; private boolean blockades; private ArrayList<StandardEntity> roads; private final double MAX_PROPORTION_ROADS = 0.2; private final int MAX_ROADS_TO_CONSIDER = 20; private IAMCommunicationModule commModule; private boolean stillStuck = false; private static final Logger LOGGER = Logger .getLogger(ClashRandomisedClosestSearchBehaviour.class); private static final String BLOCKADE_KEY = "collapse.create-road-blockages"; private static final int DISTANCE = 50000; public ClashRandomisedClosestSearchBehaviour(IAMWorldModel worldModel, EntityID myself, IExecutionService executionService, IRoutingModule routingModule, Config config, IAMCommunicationModule commModule) { this.blockades = true;// config.getBooleanValue(BLOCKADE_KEY, true); this.worldModel = worldModel; this.myself = myself; this.executionService = executionService; this.routingModule = routingModule; this.commModule = commModule; roads = new ArrayList<StandardEntity>(worldModel .getEntitiesOfType(StandardEntityURN.ROAD)); } @Override public void doDefaultSearch() { if (LOGGER.isTraceEnabled()) { LOGGER.trace("Starting search."); Collection<EntityID> unknown = worldModel.getUnknownBuildings(); Collection<EntityID> safeUnsearched = worldModel .getSafeUnsearchedBuildings(); LOGGER.trace("Unknown: " + unknown.toString()); LOGGER.trace("Safe Unsearched: " + safeUnsearched.toString()); } // restrict to my search preferences Collection<StandardEntity> range = worldModel.getObjectsInRange(myself, DISTANCE); IPath searchPath; if (shareLocation()) { // ArrayList<EntityID> preferenceList = // modulatedList(buildings); ArrayList<EntityID> buildings = new ArrayList<EntityID>(); buildings.addAll(filterByDistance(range,worldModel.getSafeHigh())); int divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getUnknownHigh())); if (buildings.size() == 0) { buildings.addAll(filterByDistance(range,worldModel .getModulatedSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getModulatedUnknownBuildings())); if (buildings.size() == 0) { buildings.addAll(filterByDistance(range,worldModel .getSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getUnknownBuildings())); searchPath = visitClosestBuilding(buildings, divider); } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(filterByDistance(range,worldModel .getSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getUnknownBuildings())); searchPath = visitClosestBuilding(buildings,divider); } } } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(filterByDistance(range,worldModel .getModulatedSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel .getModulatedUnknownBuildings())); if (buildings.size() == 0) { buildings.addAll(filterByDistance(range,worldModel .getSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getUnknownBuildings())); searchPath = visitClosestBuilding(buildings, divider); } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(filterByDistance(range,worldModel .getSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel .getUnknownBuildings())); searchPath = visitClosestBuilding(buildings, divider); } } } } if(buildings.size()==0){ buildings.addAll(worldModel.getSafeHigh()); divider = buildings.size(); buildings.addAll(worldModel.getUnknownHigh()); if (buildings.size() == 0) { buildings.addAll(worldModel .getModulatedSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel.getModulatedUnknownBuildings()); if (buildings.size() == 0) { buildings.addAll(worldModel .getSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel.getUnknownBuildings()); searchPath = visitClosestBuilding(buildings, divider); } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(worldModel .getSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel.getUnknownBuildings()); searchPath = visitClosestBuilding(buildings,divider); } } } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(worldModel .getModulatedSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel .getModulatedUnknownBuildings()); if (buildings.size() == 0) { buildings.addAll(worldModel .getSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel.getUnknownBuildings()); searchPath = visitClosestBuilding(buildings, divider); } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(worldModel .getSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel .getUnknownBuildings()); searchPath = visitClosestBuilding(buildings, divider); } } } } } } else { ArrayList<EntityID> buildings = new ArrayList<EntityID>(); int divider = 0; buildings.addAll(filterByDistance(range,worldModel.getSafeHigh())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getUnknownHigh())); if (buildings.size() == 0) { buildings.addAll(filterByDistance(range,worldModel.getSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getUnknownBuildings())); searchPath = visitClosestBuilding(buildings, divider); } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(filterByDistance(range,worldModel .getSafeUnsearchedBuildings())); divider = buildings.size(); buildings.addAll(filterByDistance(range,worldModel.getUnknownBuildings())); searchPath = visitClosestBuilding(buildings, divider); } } if(buildings.size()==0){ divider = 0; buildings.addAll(worldModel.getSafeHigh()); divider = buildings.size(); buildings.addAll(worldModel.getUnknownHigh()); if (buildings.size() == 0) { buildings.addAll(worldModel.getSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel.getUnknownBuildings()); searchPath = visitClosestBuilding(buildings, divider); } else { searchPath = visitClosestBuilding(buildings, divider); if (!searchPath.isValid()) { buildings.addAll(worldModel .getSafeUnsearchedBuildings()); divider = buildings.size(); buildings.addAll(worldModel.getUnknownBuildings()); searchPath = visitClosestBuilding(buildings, divider); } } } } if (!searchPath.isValid()) { if (blockades) { searchPath = goToClosestUnseenRoad(range); if (!searchPath.isValid()) { searchPath = visitOldestRoad(roads,range); } } else { searchPath = visitOldestRoad(roads,range); } } if (searchPath.isValid()) { MoveCommand move = new MoveCommand(searchPath); if (searchPath.getLocations().size() > 0) { AbstractIAMAgent.stopIfInterrupted(); executionService.execute(move); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Search path: " + searchPath); } } stillStuck = false; } else { RandomMoveCommand random = new RandomMoveCommand(); AbstractIAMAgent.stopIfInterrupted(); executionService.execute(random); if (LOGGER.isInfoEnabled()) { LOGGER.info("Could not route anywhere. " + "Stepping to random neighbour. " + "I am probably stuck."); } if (!stillStuck) { AgentStuckMessage help = new AgentStuckMessage(myself, ((Human) worldModel.getEntity(myself)) .getPosition()); help.setPriority(MessagePriority.CRITICAL); // I'll repeat this anyway while I am stuck help.setTTL(10); commModule.enqueueRadioMessageToOwnTeam(help); stillStuck = true; } } } public Collection<EntityID> filterByDistance(Collection<StandardEntity> withinRange, Collection<EntityID> interest){ // withinRange - objects in range // interest - set to filter FastSet<EntityID> filtered = new FastSet<EntityID>(); for(Iterator<StandardEntity> it = withinRange.iterator(); it.hasNext();){ StandardEntity e = (StandardEntity) it.next(); if(interest.contains(e.getID())){ filtered.add(e.getID()); } } return filtered; } public ArrayList<StandardEntity> filterByDistance(Collection<StandardEntity> withinRange, Collection<StandardEntity> interest){ // withinRange - objects in range // interest - set to filter ArrayList<StandardEntity> filtered = new ArrayList<StandardEntity>(); for(Iterator<StandardEntity> it = withinRange.iterator(); it.hasNext();){ StandardEntity e = (StandardEntity) it.next(); if(interest.contains(e)){ filtered.add(e); } } return filtered; } /* * decides if an agent is sharing a location with another */ private boolean shareLocation() { Collection<StandardEntity> agents = worldModel.getEntitiesOfType( StandardEntityURN.AMBULANCE_TEAM, StandardEntityURN.POLICE_FORCE); int loc = ((Human) worldModel.getEntity(myself)).getPosition() .getValue(); for (Iterator<StandardEntity> it = agents.iterator(); it.hasNext();) { StandardEntity agent = it.next(); if (((Human) agent).isPositionDefined() && agent.getID().getValue() != myself.getValue()) { if (((Human) agent).getPosition().getValue() == loc) { return true; } } } return false; } /* * returns the load visited the longest time ago */ private IPath visitOldestRoad(ArrayList<StandardEntity> roads, Collection<StandardEntity> range) { ArrayList<StandardEntity> filtered = filterByDistance(range,roads); if(filtered.size()>0){ Collections.sort(filtered, new RoadComparator(worldModel)); IPath path = Path.INVALID_PATH; int endIndex = (int) (MAX_PROPORTION_ROADS * filtered.size()); if (endIndex == filtered.size()) { endIndex = filtered.size() - 1; } else if (endIndex == 0) { endIndex = 1; } List<EntityID> targets = new ArrayList<EntityID>(endIndex); for (int i = 0; i <= endIndex; i++) { targets.add(filtered.get(i).getID()); } path = routingModule.findShortestPath(myself, targets); return path; } else { Collections.sort(roads, new RoadComparator(worldModel)); IPath path = Path.INVALID_PATH; int endIndex = (int) (MAX_PROPORTION_ROADS * roads.size()); if (endIndex == roads.size()) { endIndex = roads.size() - 1; } else if (endIndex == 0) { endIndex = 1; } List<EntityID> targets = new ArrayList<EntityID>(endIndex); for (int i = 0; i <= endIndex; i++) { targets.add(roads.get(i).getID()); } path = routingModule.findShortestPath(myself, targets); return path; } } private IPath visitClosestBuilding(ArrayList<EntityID> buildings, int index) { if (buildings.size() > 0) { IPath path = routingModule.findShortestPath(myself, buildings); if (path.isValid()) { List<EntityID> locations = path.getLocations(); EntityID destination = locations.get(locations.size() - 1); int pos = buildings.indexOf(destination); if (pos < index) { // safeUnsearched return path; } else { // unKnown List<PositionXY> positions = path.getXYPath(); locations = locations.subList(0, locations.size() - 1); positions = positions.subList(0, positions.size() - 1); return new Path(locations, positions); } } else { return Path.INVALID_PATH; } } else { return Path.INVALID_PATH; } } /** * @return */ private IPath goToClosestUnseenRoad(Collection<StandardEntity> range) { Collection<StandardEntity> roads = worldModel.getEntitiesOfType(StandardEntityURN.ROAD); ArrayList<StandardEntity> filtered = filterByDistance(range,roads); if(filtered.size()==0){ Collection<EntityID> unseenRoads = new FastList<EntityID>(); for (StandardEntity road : roads) { Road r = (Road) road; if (!r.isBlockadesDefined()) { unseenRoads.add(r.getID()); } } if (unseenRoads.size() > 0) { IPath path = routingModule.findShortestPath(myself, unseenRoads); if (LOGGER.isDebugEnabled() && path.isValid()) { LOGGER.debug("Going to unknown road " + worldModel.getEntity( path.getLocations().get( path.getLocations().size() - 1)) .getFullDescription() + " from " + worldModel.getEntity(myself).getFullDescription() + " on " + worldModel.getEntity(myself).getFullDescription() + " using path: " + path.toString()); } return path; } else { return Path.INVALID_PATH; } } else { Collection<EntityID> unseenRoads = new FastList<EntityID>(); for (StandardEntity road : filtered) { Road r = (Road) road; if (!r.isBlockadesDefined()) { unseenRoads.add(r.getID()); } } if (unseenRoads.size() > 0) { IPath path = routingModule.findShortestPath(myself, unseenRoads); if (LOGGER.isDebugEnabled() && path.isValid()) { LOGGER.debug("Going to unknown road " + worldModel.getEntity( path.getLocations().get( path.getLocations().size() - 1)) .getFullDescription() + " from " + worldModel.getEntity(myself).getFullDescription() + " on " + worldModel.getEntity(myself).getFullDescription() + " using path: " + path.toString()); } return path; } else { return Path.INVALID_PATH; } } } }