diff --git a/.gitignore b/.gitignore index 6119e70..41060c9 100644 --- a/.gitignore +++ b/.gitignore @@ -173,3 +173,4 @@ cython_debug/ # ADF agent.log* precompute +!java/lib/src/main/java/adf_core_python/core/agent/precompute diff --git a/adf_core_python/core/gateway/gateway_agent.py b/adf_core_python/core/gateway/gateway_agent.py index 036c49a..31008bb 100644 --- a/adf_core_python/core/gateway/gateway_agent.py +++ b/adf_core_python/core/gateway/gateway_agent.py @@ -2,7 +2,7 @@ from typing import Optional, TYPE_CHECKING, Callable -from rcrs_core.connection import RCRSProto_pb2 +from rcrs_core.connection import RCRSProto_pb2, URN from adf_core_python.core.agent.info.agent_info import AgentInfo from adf_core_python.core.agent.info.scenario_info import ScenarioInfo @@ -111,3 +111,8 @@ def message_received(self, msg: RCRSProto_pb2) -> None: self._gateway_modules[c_msg.module_id].set_execute_response(c_msg.result) self._gateway_modules[c_msg.module_id].set_is_executed(True) + + if msg.urn == URN.Command.AK_SPEAK: + if self.send_msg is None: + raise RuntimeError("send_msg is None") + self.send_msg(msg) diff --git a/adf_core_python/launcher.py b/adf_core_python/launcher.py index 89cb927..94d0c6e 100644 --- a/adf_core_python/launcher.py +++ b/adf_core_python/launcher.py @@ -1,4 +1,5 @@ import argparse +import resource from adf_core_python.core.config.config import Config from adf_core_python.core.launcher.agent_launcher import AgentLauncher @@ -11,6 +12,8 @@ def __init__( self, launcher_config_file: str, ) -> None: + resource.setrlimit(resource.RLIMIT_NOFILE, (8192, 9223372036854775807)) + configure_logger() self.logger = get_logger(__name__) diff --git a/java/lib/build.gradle b/java/lib/build.gradle index 386d59b..61869cf 100644 --- a/java/lib/build.gradle +++ b/java/lib/build.gradle @@ -39,6 +39,9 @@ dependencies { implementation 'org.apache.logging.log4j:log4j-core:2.24.2' implementation 'org.apache.logging.log4j:log4j-api:2.24.2' + //Algorithm + implementation 'com.google.common:google-collect:0.5' + testImplementation libs.junit.jupiter testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/java/lib/src/main/java/adf_core_python/Main.java b/java/lib/src/main/java/adf_core_python/Main.java index d6fbd5f..a85ba19 100644 --- a/java/lib/src/main/java/adf_core_python/Main.java +++ b/java/lib/src/main/java/adf_core_python/Main.java @@ -1,6 +1,6 @@ package adf_core_python; -import adf_core_python.gateway.Gateway; +import adf_core_python.core.gateway.Gateway; public class Main { public static void main(String[] args) { diff --git a/java/lib/src/main/java/adf_core_python/agent/develop/DevelopData.java b/java/lib/src/main/java/adf_core_python/agent/develop/DevelopData.java deleted file mode 100644 index 00652e6..0000000 --- a/java/lib/src/main/java/adf_core_python/agent/develop/DevelopData.java +++ /dev/null @@ -1,40 +0,0 @@ -package adf_core_python.agent.develop; - -import jakarta.annotation.Nonnull; - -import java.util.List; -import java.util.Map; - -public class DevelopData { - private boolean developFlag = false; - - private Map intValues; - private Map doubleValues; - private Map stringValues; - private Map boolValues; - - private Map> intLists; - private Map> doubleLists; - private Map> stringLists; - private Map> boolLists; - - @Nonnull - public Integer getInteger(@Nonnull String name, int defaultValue) { - if (this.developFlag) { - Integer value = this.intValues.get(name); - if (value == null) { - String rawData = this.stringValues.get(name); - if (rawData != null && !rawData.equals("")) { - value = Integer.valueOf(rawData); - } - if (value != null) { - this.intValues.put(name, value); - } - } - if (value != null) { - return value; - } - } - return defaultValue; - } -} diff --git a/java/lib/src/main/java/adf_core_python/agent/Agent.java b/java/lib/src/main/java/adf_core_python/core/agent/Agent.java similarity index 62% rename from java/lib/src/main/java/adf_core_python/agent/Agent.java rename to java/lib/src/main/java/adf_core_python/core/agent/Agent.java index 07c9f0a..5524e7d 100644 --- a/java/lib/src/main/java/adf_core_python/agent/Agent.java +++ b/java/lib/src/main/java/adf_core_python/core/agent/Agent.java @@ -1,22 +1,28 @@ -package adf_core_python.agent; +package adf_core_python.core.agent; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.communication.standard.bundle.StandardMessageBundle; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.config.ModuleConfig; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.AbstractModule; -import adf_core_python.gateway.mapper.AbstractMapper; -import adf_core_python.gateway.mapper.MapperDict; +import adf.core.launcher.ConsoleOutput; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.communication.standard.StandardCommunicationModule; +import adf_core_python.core.agent.config.ModuleConfig; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.communication.CommunicationModule; +import adf_core_python.core.component.module.AbstractModule; +import adf_core_python.core.gateway.Coordinator; +import adf_core_python.core.gateway.mapper.AbstractMapper; +import adf_core_python.core.gateway.mapper.MapperDict; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import rescuecore2.config.Config; import rescuecore2.messages.Command; +import rescuecore2.messages.Message; import rescuecore2.standard.entities.StandardEntityURN; import rescuecore2.standard.entities.StandardWorldModel; import rescuecore2.worldmodel.ChangeSet; @@ -25,14 +31,15 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Objects; public class Agent { - private final AgentInfo agentInfo; - private final WorldInfo worldInfo; - private final ScenarioInfo scenarioInfo; + public final AgentInfo agentInfo; + public final WorldInfo worldInfo; + public final ScenarioInfo scenarioInfo; private final ModuleManager moduleManager; private final DevelopData developData; private final PrecomputeData precomputeData; @@ -40,17 +47,24 @@ public class Agent { private final HashMap modules = new HashMap<>(); private final MapperDict mapperDict; private final Logger logger; + private final Coordinator coordinator; + private CommunicationModule communicationModule; + private int ignoreTime; - public Agent(EntityID entityID, Collection entities, ScenarioInfo scenarioInfo, DevelopData developData, ModuleConfig moduleConfig) { + public Agent(EntityID entityID, Collection entities, ScenarioInfo scenarioInfo, DevelopData developData, ModuleConfig moduleConfig, Coordinator coordinator) { StandardWorldModel worldModel = new StandardWorldModel(); worldModel.addEntities(entities); worldModel.index(); + this.ignoreTime = scenarioInfo.getRawConfig() + .getIntValue(kernel.KernelConstants.IGNORE_AGENT_COMMANDS_KEY); + this.agentInfo = new AgentInfo(entityID, worldModel); this.worldInfo = new WorldInfo(worldModel); this.scenarioInfo = scenarioInfo; this.developData = developData; this.moduleManager = new ModuleManager(this.agentInfo, this.worldInfo, this.scenarioInfo, moduleConfig, this.developData); + this.coordinator = coordinator; String dataStorageName = ""; StandardEntityURN agentURN = Objects.requireNonNull(this.worldInfo.getEntity(this.agentInfo.getID())).getStandardURN(); @@ -97,13 +111,48 @@ public Class registerModule(@Nonnull String moduleID, @Nonnull String moduleN } public void update(int time, ChangeSet changed, Collection heard) { + worldInfo.setTime(time); + worldInfo.merge(changed); agentInfo.recordThinkStartTime(); agentInfo.setTime(time); + + if (time == 1) { + if (this.communicationModule != null) { + ConsoleOutput.out(ConsoleOutput.State.ERROR, + "[ERROR ] Loader is not found."); + ConsoleOutput.out(ConsoleOutput.State.NOTICE, + "CommunicationModule is modified - " + this); + } else { + this.communicationModule = new StandardCommunicationModule(); + } + + this.messageManager.registerMessageBundle(new StandardMessageBundle()); + } + + // agents can subscribe after ignore time + if (time >= ignoreTime) { + this.messageManager.subscribe(this.agentInfo, this.worldInfo, + this.scenarioInfo); + + if (!this.messageManager.getIsSubscribed()) { + int[] channelsToSubscribe = this.messageManager.getChannels(); + if (channelsToSubscribe != null) { + this.messageManager.setIsSubscribed(true); + } + } + } + agentInfo.setHeard(heard); agentInfo.setChanged(changed); - worldInfo.setTime(time); - worldInfo.merge(changed); worldInfo.setChanged(changed); + + this.messageManager.refresh(); + this.communicationModule.receive(this, this.messageManager); + + this.messageManager.coordinateMessages(this.agentInfo, this.worldInfo, + this.scenarioInfo); + this.communicationModule.send(this, this.messageManager); + logger.debug("Agent Update (Time: {}, Changed: {}, Heard: {})", agentInfo.getTime(), agentInfo.getChanged(), agentInfo.getHeard()); } @@ -113,4 +162,12 @@ public Config execModuleMethod(String moduleID, String methodName, Config argume logger.debug("Executed Method Result (MethodName: {}, Result: {}", methodName, result); return result; } + + public EntityID getID() { + return this.agentInfo.getID(); + } + + public void send(Message[] messages) { + Arrays.stream(messages).forEach(coordinator::sendMessage); + } } diff --git a/java/lib/src/main/java/adf_core_python/core/agent/communication/MessageManager.java b/java/lib/src/main/java/adf_core_python/core/agent/communication/MessageManager.java new file mode 100644 index 0000000..e82e0a5 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/core/agent/communication/MessageManager.java @@ -0,0 +1,240 @@ +package adf_core_python.core.agent.communication; + +import adf.core.agent.communication.standard.bundle.StandardMessageBundle; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf.core.component.communication.CommunicationMessage; +import adf.core.component.communication.MessageBundle; +import adf.core.launcher.ConsoleOutput; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.component.communication.ChannelSubscriber; +import adf_core_python.core.component.communication.MessageCoordinator; +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; + +import java.util.*; + +public class MessageManager { + + private final HashMap> messageClassMap; + private final HashMap, + Integer> messageClassIDMap; + private final ArrayList sendMessageList; + private final List receivedMessageList; + private final Set checkDuplicationCache; + private int standardMessageClassCount; + private int customMessageClassCount; + private List> channelSendMessageList; + private int heardAgentHelpCount; + private MessageCoordinator messageCoordinator; + private ChannelSubscriber channelSubscriber; + private int[] subscribedChannels; + private boolean isSubscribed; + + public MessageManager() { + this.standardMessageClassCount = 1; // 00001 + this.customMessageClassCount = 16; // 10000 + this.messageClassMap = new HashMap<>(32); + this.messageClassIDMap = new HashMap<>(32); + this.sendMessageList = new ArrayList<>(); + this.channelSendMessageList = new ArrayList<>(); + this.checkDuplicationCache = new HashSet<>(); + this.receivedMessageList = new ArrayList<>(); + this.heardAgentHelpCount = 0; + + this.messageCoordinator = null; + + channelSubscriber = null; + subscribedChannels = new int[1]; + // by default subscribe to channel 1 + subscribedChannels[0] = 1; + isSubscribed = false; + } + + + public void subscribeToChannels(int[] channels) { + subscribedChannels = channels; + isSubscribed = false; + } + + + public int[] getChannels() { + return subscribedChannels; + } + + + public boolean getIsSubscribed() { + return isSubscribed; + } + + + public void setIsSubscribed(boolean subscribed) { + isSubscribed = subscribed; + } + + + public void setMessageCoordinator(MessageCoordinator mc) { + this.messageCoordinator = mc; + } + + + public void setChannelSubscriber(ChannelSubscriber cs) { + channelSubscriber = cs; + } + + + public void subscribe(AgentInfo agentInfo, WorldInfo worldInfo, + ScenarioInfo scenarioInfo) { + if (channelSubscriber != null) { + channelSubscriber.subscribe(agentInfo, worldInfo, scenarioInfo, this); + } + } + + + public boolean registerMessageClass(int index, + @Nonnull Class messageClass) { + if (index > 31) { + throw new IllegalArgumentException("index maximum is 31"); + } + + if (messageClassMap.containsKey(index)) { + ConsoleOutput.out(ConsoleOutput.State.WARN, + "index(" + index + ") is already registered/" + messageClass.getName() + + " is ignored"); + return false; + } + + messageClassMap.put(index, messageClass); + messageClassIDMap.put(messageClass, index); + + return true; + } + + + public void registerMessageBundle(@Nonnull MessageBundle messageBundle) { + if (messageBundle == null) { + return; + } + + for (Class messageClass : messageBundle + .getMessageClassList()) { + this.registerMessageClass( + (messageBundle.getClass().equals(StandardMessageBundle.class) + ? standardMessageClassCount++ + : customMessageClassCount++), + messageClass); + } + } + + + @Nullable + public Class getMessageClass(int index) { + if (!messageClassMap.containsKey(index)) { + return null; + } + + return messageClassMap.get(index); + } + + + public int getMessageClassIndex(@Nonnull CommunicationMessage message) { + if (!messageClassMap.containsValue(message.getClass())) { + throw new IllegalArgumentException( + message.getClass().getName() + " is not registered with the manager"); + } + + return messageClassIDMap.get(message.getClass()); + } + + + public void addMessage(@Nonnull CommunicationMessage message) { + this.addMessage(message, true); + } + + + public void addMessage(@Nonnull CommunicationMessage message, + boolean checkDuplication) { + if (message == null) { + return; + } + + String checkKey = message.getCheckKey(); + if (checkDuplication && !this.checkDuplicationCache.contains(checkKey)) { + this.sendMessageList.add(message); + this.checkDuplicationCache.add(checkKey); + } else { + this.sendMessageList.add(message); + this.checkDuplicationCache.add(checkKey); + } + } + + + @Nonnull + public List> getSendMessageList() { + return this.channelSendMessageList; + } + + + public void addReceivedMessage(@Nonnull CommunicationMessage message) { + receivedMessageList.add(message); + } + + + @Nonnull + public List getReceivedMessageList() { + return this.receivedMessageList; + } + + + @SafeVarargs + @Nonnull + public final List getReceivedMessageList( + Class... messageClasses) { + List resultList = new ArrayList<>(); + for (CommunicationMessage message : this.receivedMessageList) { + for (Class< + ? extends CommunicationMessage> messageClass : messageClasses) { + if (messageClass.isAssignableFrom(message.getClass())) { + resultList.add(message); + } + } + } + return resultList; + } + + + public void coordinateMessages(AgentInfo agentInfo, WorldInfo worldInfo, + ScenarioInfo scenarioInfo) { + // create a list of messages for every channel including the voice comm + // channel + this.channelSendMessageList = new ArrayList>( + scenarioInfo.getCommsChannelsCount()); + for (int i = 0; i < scenarioInfo.getCommsChannelsCount(); i++) { + this.channelSendMessageList.add(new ArrayList()); + } + + if (messageCoordinator != null) { + messageCoordinator.coordinate(agentInfo, worldInfo, scenarioInfo, this, + this.sendMessageList, this.channelSendMessageList); + } + } + + + public void addHeardAgentHelpCount() { + this.heardAgentHelpCount++; + } + + + public int getHeardAgentHelpCount() { + return this.heardAgentHelpCount; + } + + + public void refresh() { + this.sendMessageList.clear(); + this.checkDuplicationCache.clear(); + this.receivedMessageList.clear(); + this.heardAgentHelpCount = 0; + } +} diff --git a/java/lib/src/main/java/adf_core_python/core/agent/communication/standard/StandardCommunicationModule.java b/java/lib/src/main/java/adf_core_python/core/agent/communication/standard/StandardCommunicationModule.java new file mode 100644 index 0000000..90bf17d --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/core/agent/communication/standard/StandardCommunicationModule.java @@ -0,0 +1,175 @@ +package adf_core_python.core.agent.communication.standard; + +import adf.core.agent.communication.standard.bundle.StandardMessage; +import adf.core.component.communication.CommunicationMessage; +import adf.core.component.communication.util.BitOutputStream; +import adf.core.component.communication.util.BitStreamReader; +import adf.core.launcher.ConsoleOutput; +import adf_core_python.core.agent.Agent; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.component.communication.CommunicationModule; +import jakarta.annotation.Nonnull; +import rescuecore2.messages.Command; +import rescuecore2.messages.Message; +import rescuecore2.standard.messages.AKSpeak; +import rescuecore2.worldmodel.EntityID; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +public class StandardCommunicationModule extends CommunicationModule { + + final Class[] standardMessageArgTypes = {boolean.class, int.class, + int.class, BitStreamReader.class}; + final private int ESCAPE_CHAR = 0x41; + final private int SIZE_ID = 5; + final private int SIZE_TTL = 3; + + @Override + public void receive(@Nonnull Agent agent, + @Nonnull MessageManager messageManager) { + Collection heardList = agent.agentInfo.getHeard(); + + for (Command heard : heardList) { + if (heard instanceof AKSpeak) { + EntityID senderID = heard.getAgentID(); + + if (agent.getID().equals(senderID)) { + continue; + } + + AKSpeak received = (AKSpeak) heard; + byte[] receivedData = received.getContent(); + boolean isRadio = (received.getChannel() != 0); + + if (receivedData.length <= 0) { + continue; + } + + if (isRadio) { + addReceivedMessage(messageManager, Boolean.TRUE, senderID, + receivedData); + } else { + String voiceString = new String(receivedData); + if ("Help".equalsIgnoreCase(voiceString) + || "Ouch".equalsIgnoreCase(voiceString)) { + messageManager.addHeardAgentHelpCount(); + continue; + } + + BitOutputStream messageTemp = new BitOutputStream(); + for (int i = 0; i < receivedData.length; i++) { + if (receivedData[i] == ESCAPE_CHAR) { + if ((i + 1) >= receivedData.length) { + addReceivedMessage(messageManager, Boolean.FALSE, senderID, + messageTemp.toByteArray()); + break; + } else if (receivedData[i + 1] != ESCAPE_CHAR) { + addReceivedMessage(messageManager, Boolean.FALSE, senderID, + messageTemp.toByteArray()); + messageTemp.reset(); + continue; + } + + i += 1; + } + messageTemp.write(receivedData[i]); + } + } + } + } + } + + private void addReceivedMessage(@Nonnull MessageManager messageManager, + boolean isRadio, @Nonnull EntityID senderID, byte[] data) { + BitStreamReader bitStreamReader = new BitStreamReader(data); + int messageClassIndex = bitStreamReader.getBits(SIZE_ID); + if (messageClassIndex <= 0) { + ConsoleOutput.out(ConsoleOutput.State.WARN, + "ignore Message Class Index (0)"); + return; + } + + int messageTTL = (isRadio ? -1 : bitStreamReader.getBits(SIZE_TTL)); + + Object[] args = {Boolean.valueOf(isRadio), + Integer.valueOf(senderID.getValue()), Integer.valueOf(messageTTL), + bitStreamReader}; + try { + messageManager + .addReceivedMessage(messageManager.getMessageClass(messageClassIndex) + .getConstructor(standardMessageArgTypes).newInstance(args)); + } catch (NoSuchMethodException | IllegalArgumentException e) { + e.printStackTrace(); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + } + + + @Override + public void send(@Nonnull Agent agent, + @Nonnull MessageManager messageManager) { + final int voiceLimitBytes = agent.scenarioInfo.getVoiceMessagesSize(); + int voiceMessageLeft = voiceLimitBytes; + ByteArrayOutputStream voiceMessageStream = new ByteArrayOutputStream(); + + Message[] messages = new Message[1]; + + List> sendMessageList = messageManager + .getSendMessageList(); + for (int channel = 0; channel < sendMessageList.size(); channel++) { + for (CommunicationMessage message : sendMessageList.get(channel)) { + int messageClassIndex = messageManager.getMessageClassIndex(message); + + BitOutputStream bitOutputStream = new BitOutputStream(); + bitOutputStream.writeBits(messageClassIndex, SIZE_ID); + + if (channel == 0) { + bitOutputStream.writeBits(((StandardMessage) message).getTTL(), + SIZE_TTL); + } + + bitOutputStream.writeBits(message.toBitOutputStream()); + + if (channel > 0) { + messages[0] = new AKSpeak(agent.getID(), agent.agentInfo.getTime(), + channel, bitOutputStream.toByteArray()); + agent.send(messages); + } else { + // voice channel + int messageSize = (int) Math + .ceil(((double) bitOutputStream.size()) / 8.0); + if (messageSize <= voiceMessageLeft) { + byte[] messageData = bitOutputStream.toByteArray(); + ByteArrayOutputStream escapedMessage = new ByteArrayOutputStream(); + for (int i = 0; i < messageSize; i++) { + if (messageData[i] == ESCAPE_CHAR) { + escapedMessage.write(ESCAPE_CHAR); + } + escapedMessage.write(messageData[i]); + } + escapedMessage.toByteArray(); + escapedMessage.write(ESCAPE_CHAR); + if (escapedMessage.size() <= voiceMessageLeft) { + voiceMessageLeft -= escapedMessage.size(); + try { + voiceMessageStream.write(escapedMessage.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + } + } + + if (voiceMessageStream.size() > 0) { + messages[0] = new AKSpeak(agent.getID(), agent.agentInfo.getTime(), 0, + voiceMessageStream.toByteArray()); + agent.send(messages); + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/agent/config/ModuleConfig.java b/java/lib/src/main/java/adf_core_python/core/agent/config/ModuleConfig.java similarity index 96% rename from java/lib/src/main/java/adf_core_python/agent/config/ModuleConfig.java rename to java/lib/src/main/java/adf_core_python/core/agent/config/ModuleConfig.java index 3232d7a..7a6f4de 100644 --- a/java/lib/src/main/java/adf_core_python/agent/config/ModuleConfig.java +++ b/java/lib/src/main/java/adf_core_python/core/agent/config/ModuleConfig.java @@ -1,4 +1,4 @@ -package adf_core_python.agent.config; +package adf_core_python.core.agent.config; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/java/lib/src/main/java/adf_core_python/agent/info/AgentInfo.java b/java/lib/src/main/java/adf_core_python/core/agent/info/AgentInfo.java similarity index 98% rename from java/lib/src/main/java/adf_core_python/agent/info/AgentInfo.java rename to java/lib/src/main/java/adf_core_python/core/agent/info/AgentInfo.java index e0d63d1..0a2e4f4 100644 --- a/java/lib/src/main/java/adf_core_python/agent/info/AgentInfo.java +++ b/java/lib/src/main/java/adf_core_python/core/agent/info/AgentInfo.java @@ -1,4 +1,4 @@ -package adf_core_python.agent.info; +package adf_core_python.core.agent.info; import adf.core.agent.action.Action; import jakarta.annotation.Nonnull; diff --git a/java/lib/src/main/java/adf_core_python/agent/module/ModuleManager.java b/java/lib/src/main/java/adf_core_python/core/agent/module/ModuleManager.java similarity index 97% rename from java/lib/src/main/java/adf_core_python/agent/module/ModuleManager.java rename to java/lib/src/main/java/adf_core_python/core/agent/module/ModuleManager.java index abc0621..68c7254 100644 --- a/java/lib/src/main/java/adf_core_python/agent/module/ModuleManager.java +++ b/java/lib/src/main/java/adf_core_python/core/agent/module/ModuleManager.java @@ -1,5 +1,6 @@ -package adf_core_python.agent.module; +package adf_core_python.core.agent.module; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; import adf.core.component.centralized.CommandExecutor; @@ -7,11 +8,10 @@ import adf.core.component.communication.ChannelSubscriber; import adf.core.component.communication.CommunicationMessage; import adf.core.component.communication.MessageCoordinator; -import adf.core.component.extaction.ExtAction; -import adf_core_python.agent.config.ModuleConfig; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.component.module.AbstractModule; +import adf_core_python.core.agent.config.ModuleConfig; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.component.extaction.ExtAction; +import adf_core_python.core.component.module.AbstractModule; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.apache.logging.log4j.LogManager; @@ -67,6 +67,7 @@ public ModuleManager(@Nonnull AgentInfo agentInfo, @Nonnull WorldInfo worldInfo, Class moduleClass; try { moduleClass = Class.forName(className); + logger.info(moduleClass.getName()); } catch (ClassNotFoundException | NullPointerException e) { logger.warn("Module " + moduleName + " not found. Using default class " + defaultClassName); className = defaultClassName; @@ -89,7 +90,7 @@ public ModuleManager(@Nonnull AgentInfo agentInfo, @Nonnull WorldInfo worldInfo, } throw new IllegalArgumentException( - "Module name is not found : " + className); + "Module is not found : " + className); } diff --git a/java/lib/src/main/java/adf_core_python/agent/precompute/PreData.java b/java/lib/src/main/java/adf_core_python/core/agent/precompute/PreData.java similarity index 97% rename from java/lib/src/main/java/adf_core_python/agent/precompute/PreData.java rename to java/lib/src/main/java/adf_core_python/core/agent/precompute/PreData.java index 847b4f7..aea850f 100644 --- a/java/lib/src/main/java/adf_core_python/agent/precompute/PreData.java +++ b/java/lib/src/main/java/adf_core_python/core/agent/precompute/PreData.java @@ -1,4 +1,4 @@ -package adf_core_python.agent.precompute; +package adf_core_python.core.agent.precompute; import java.util.HashMap; import java.util.List; diff --git a/java/lib/src/main/java/adf_core_python/agent/precompute/PrecomputeData.java b/java/lib/src/main/java/adf_core_python/core/agent/precompute/PrecomputeData.java similarity index 99% rename from java/lib/src/main/java/adf_core_python/agent/precompute/PrecomputeData.java rename to java/lib/src/main/java/adf_core_python/core/agent/precompute/PrecomputeData.java index d838c68..583d401 100644 --- a/java/lib/src/main/java/adf_core_python/agent/precompute/PrecomputeData.java +++ b/java/lib/src/main/java/adf_core_python/core/agent/precompute/PrecomputeData.java @@ -1,4 +1,4 @@ -package adf_core_python.agent.precompute; +package adf_core_python.core.agent.precompute; import adf.core.agent.info.WorldInfo; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/java/lib/src/main/java/adf_core_python/core/component/communication/ChannelSubscriber.java b/java/lib/src/main/java/adf_core_python/core/component/communication/ChannelSubscriber.java new file mode 100644 index 0000000..5a017b4 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/core/component/communication/ChannelSubscriber.java @@ -0,0 +1,19 @@ +package adf_core_python.core.component.communication; + +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; + +public class ChannelSubscriber { + + public void subscribe(AgentInfo agentInfo, WorldInfo worldInfo, + ScenarioInfo scenarioInfo, MessageManager messageManager) { + // default channel subscriber subscribes to only channel 1 + if (agentInfo.getTime() == 1) { + int[] channels = new int[1]; + channels[0] = 1; + messageManager.subscribeToChannels(channels); + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/core/component/communication/CommunicationModule.java b/java/lib/src/main/java/adf_core_python/core/component/communication/CommunicationModule.java new file mode 100644 index 0000000..b5135a1 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/core/component/communication/CommunicationModule.java @@ -0,0 +1,11 @@ +package adf_core_python.core.component.communication; + +import adf_core_python.core.agent.Agent; +import adf_core_python.core.agent.communication.MessageManager; + +abstract public class CommunicationModule { + + abstract public void receive(Agent agent, MessageManager messageManager); + + abstract public void send(Agent agent, MessageManager messageManager); +} diff --git a/java/lib/src/main/java/adf_core_python/core/component/communication/MessageCoordinator.java b/java/lib/src/main/java/adf_core_python/core/component/communication/MessageCoordinator.java new file mode 100644 index 0000000..4ebaa2a --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/core/component/communication/MessageCoordinator.java @@ -0,0 +1,18 @@ +package adf_core_python.core.component.communication; + +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf.core.component.communication.CommunicationMessage; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; + +import java.util.ArrayList; +import java.util.List; + +abstract public class MessageCoordinator { + + abstract public void coordinate(AgentInfo agentInfo, WorldInfo worldInfo, + ScenarioInfo scenarioInfo, MessageManager messageManager, + ArrayList sendMessageList, + List> channelSendMessageList); +} diff --git a/java/lib/src/main/java/adf_core_python/component/extaction/ExtAction.java b/java/lib/src/main/java/adf_core_python/core/component/extaction/ExtAction.java similarity index 91% rename from java/lib/src/main/java/adf_core_python/component/extaction/ExtAction.java rename to java/lib/src/main/java/adf_core_python/core/component/extaction/ExtAction.java index 0dad82a..f7ba688 100644 --- a/java/lib/src/main/java/adf_core_python/component/extaction/ExtAction.java +++ b/java/lib/src/main/java/adf_core_python/core/component/extaction/ExtAction.java @@ -1,13 +1,13 @@ -package adf_core_python.component.extaction; +package adf_core_python.core.component.extaction; import adf.core.agent.action.Action; -import adf.core.agent.communication.MessageManager; import adf.core.agent.develop.DevelopData; -import adf.core.agent.info.AgentInfo; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf.core.agent.module.ModuleManager; -import adf.core.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.worldmodel.EntityID; abstract public class ExtAction { diff --git a/java/lib/src/main/java/adf_core_python/component/module/AbstractModule.java b/java/lib/src/main/java/adf_core_python/core/component/module/AbstractModule.java similarity index 91% rename from java/lib/src/main/java/adf_core_python/component/module/AbstractModule.java rename to java/lib/src/main/java/adf_core_python/core/component/module/AbstractModule.java index 830ca29..e6e6f65 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/AbstractModule.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/AbstractModule.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module; +package adf_core_python.core.component.module; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import java.util.ArrayList; import java.util.List; diff --git a/java/lib/src/main/java/adf_core_python/component/module/algorithm/Clustering.java b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/Clustering.java similarity index 84% rename from java/lib/src/main/java/adf_core_python/component/module/algorithm/Clustering.java rename to java/lib/src/main/java/adf_core_python/core/component/module/algorithm/Clustering.java index aba296d..1c84cdb 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/algorithm/Clustering.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/Clustering.java @@ -1,13 +1,13 @@ -package adf_core_python.component.module.algorithm; +package adf_core_python.core.component.module.algorithm; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.AbstractModule; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.AbstractModule; import rescuecore2.standard.entities.StandardEntity; import rescuecore2.worldmodel.EntityID; diff --git a/java/lib/src/main/java/adf_core_python/component/module/algorithm/DynamicClustering.java b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/DynamicClustering.java similarity index 61% rename from java/lib/src/main/java/adf_core_python/component/module/algorithm/DynamicClustering.java rename to java/lib/src/main/java/adf_core_python/core/component/module/algorithm/DynamicClustering.java index 208d200..16d302a 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/algorithm/DynamicClustering.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/DynamicClustering.java @@ -1,10 +1,10 @@ -package adf_core_python.component.module.algorithm; +package adf_core_python.core.component.module.algorithm; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; public abstract class DynamicClustering extends Clustering { diff --git a/java/lib/src/main/java/adf_core_python/component/module/algorithm/PathPlanning.java b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/PathPlanning.java similarity index 85% rename from java/lib/src/main/java/adf_core_python/component/module/algorithm/PathPlanning.java rename to java/lib/src/main/java/adf_core_python/core/component/module/algorithm/PathPlanning.java index 6101ac0..7a40f63 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/algorithm/PathPlanning.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/PathPlanning.java @@ -1,13 +1,13 @@ -package adf_core_python.component.module.algorithm; +package adf_core_python.core.component.module.algorithm; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.AbstractModule; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.AbstractModule; import rescuecore2.misc.Pair; import rescuecore2.worldmodel.EntityID; diff --git a/java/lib/src/main/java/adf_core_python/component/module/algorithm/StaticClustering.java b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/StaticClustering.java similarity index 61% rename from java/lib/src/main/java/adf_core_python/component/module/algorithm/StaticClustering.java rename to java/lib/src/main/java/adf_core_python/core/component/module/algorithm/StaticClustering.java index b9647da..f3fb404 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/algorithm/StaticClustering.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/algorithm/StaticClustering.java @@ -1,10 +1,10 @@ -package adf_core_python.component.module.algorithm; +package adf_core_python.core.component.module.algorithm; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; public abstract class StaticClustering extends Clustering { diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/AmbulanceTargetAllocator.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/AmbulanceTargetAllocator.java similarity index 75% rename from java/lib/src/main/java/adf_core_python/component/module/complex/AmbulanceTargetAllocator.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/AmbulanceTargetAllocator.java index 41f2e7b..4ebfb1d 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/AmbulanceTargetAllocator.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/AmbulanceTargetAllocator.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.worldmodel.EntityID; import java.util.Map; diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/BuildingDetector.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/BuildingDetector.java similarity index 75% rename from java/lib/src/main/java/adf_core_python/component/module/complex/BuildingDetector.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/BuildingDetector.java index 34567c8..cc22e34 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/BuildingDetector.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/BuildingDetector.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.standard.entities.Building; public abstract class BuildingDetector extends TargetDetector { diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/FireTargetAllocator.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/FireTargetAllocator.java similarity index 74% rename from java/lib/src/main/java/adf_core_python/component/module/complex/FireTargetAllocator.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/FireTargetAllocator.java index 65c757e..f6791d6 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/FireTargetAllocator.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/FireTargetAllocator.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.worldmodel.EntityID; import java.util.Map; diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/HumanDetector.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/HumanDetector.java similarity index 75% rename from java/lib/src/main/java/adf_core_python/component/module/complex/HumanDetector.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/HumanDetector.java index e99db72..f0491ff 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/HumanDetector.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/HumanDetector.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.standard.entities.Human; public abstract class HumanDetector extends TargetDetector { diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/PoliceTargetAllocator.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/PoliceTargetAllocator.java similarity index 74% rename from java/lib/src/main/java/adf_core_python/component/module/complex/PoliceTargetAllocator.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/PoliceTargetAllocator.java index 846dc06..4300895 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/PoliceTargetAllocator.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/PoliceTargetAllocator.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.worldmodel.EntityID; import java.util.Map; diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/RoadDetector.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/RoadDetector.java similarity index 75% rename from java/lib/src/main/java/adf_core_python/component/module/complex/RoadDetector.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/RoadDetector.java index 9f6acac..532b853 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/RoadDetector.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/RoadDetector.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.standard.entities.Road; public abstract class RoadDetector extends TargetDetector { diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/Search.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/Search.java similarity index 74% rename from java/lib/src/main/java/adf_core_python/component/module/complex/Search.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/Search.java index 13173bb..77fbe62 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/Search.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/Search.java @@ -1,12 +1,12 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; import rescuecore2.standard.entities.Area; public abstract class Search extends TargetDetector { diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/TargetAllocator.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/TargetAllocator.java similarity index 73% rename from java/lib/src/main/java/adf_core_python/component/module/complex/TargetAllocator.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/TargetAllocator.java index 3a85b34..f0b93ab 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/TargetAllocator.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/TargetAllocator.java @@ -1,13 +1,13 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.AbstractModule; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.AbstractModule; import rescuecore2.worldmodel.EntityID; import java.util.Map; diff --git a/java/lib/src/main/java/adf_core_python/component/module/complex/TargetDetector.java b/java/lib/src/main/java/adf_core_python/core/component/module/complex/TargetDetector.java similarity index 74% rename from java/lib/src/main/java/adf_core_python/component/module/complex/TargetDetector.java rename to java/lib/src/main/java/adf_core_python/core/component/module/complex/TargetDetector.java index bddd091..d0bc184 100644 --- a/java/lib/src/main/java/adf_core_python/component/module/complex/TargetDetector.java +++ b/java/lib/src/main/java/adf_core_python/core/component/module/complex/TargetDetector.java @@ -1,13 +1,13 @@ -package adf_core_python.component.module.complex; +package adf_core_python.core.component.module.complex; -import adf.core.agent.communication.MessageManager; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.agent.info.AgentInfo; -import adf_core_python.agent.module.ModuleManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.AbstractModule; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.AbstractModule; import rescuecore2.standard.entities.StandardEntity; import rescuecore2.worldmodel.EntityID; diff --git a/java/lib/src/main/java/adf_core_python/gateway/Coordinator.java b/java/lib/src/main/java/adf_core_python/core/gateway/Coordinator.java similarity index 87% rename from java/lib/src/main/java/adf_core_python/gateway/Coordinator.java rename to java/lib/src/main/java/adf_core_python/core/gateway/Coordinator.java index 309e92d..f056e94 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/Coordinator.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/Coordinator.java @@ -1,10 +1,11 @@ -package adf_core_python.gateway; +package adf_core_python.core.gateway; +import adf.core.agent.develop.DevelopData; import adf.core.agent.info.ScenarioInfo; -import adf_core_python.agent.Agent; -import adf_core_python.agent.config.ModuleConfig; -import adf_core_python.agent.develop.DevelopData; -import adf_core_python.gateway.message.*; +import adf.core.launcher.ConfigKey; +import adf_core_python.core.agent.Agent; +import adf_core_python.core.agent.config.ModuleConfig; +import adf_core_python.core.gateway.message.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import rescuecore2.config.Config; @@ -68,7 +69,12 @@ private void handleMessage(Message message) { mode = ScenarioInfo.Mode.PRECOMPUTATION_PHASE; break; } - agent = new Agent(amAgent.getAgentID(), amAgent.getEntities(), new ScenarioInfo(amAgent.getConfig(), mode), new DevelopData(), new ModuleConfig()); + Config config = amAgent.getConfig(); + agent = new Agent(amAgent.getAgentID(), amAgent.getEntities(), new ScenarioInfo(config, mode), new DevelopData( + config.getBooleanValue(ConfigKey.KEY_DEVELOP_FLAG, false), + config.getValue(ConfigKey.KEY_DEVELOP_DATA_FILE_NAME, + DevelopData.DEFAULT_FILE_NAME), + config.getArrayValue(ConfigKey.KEY_DEVELOP_DATA, "")), new ModuleConfig(), this); } else if (message instanceof AMModule amModule) { if (agent == null) { throw new IllegalStateException("Agent not found. Make sure agent has been registered."); diff --git a/java/lib/src/main/java/adf_core_python/gateway/Gateway.java b/java/lib/src/main/java/adf_core_python/core/gateway/Gateway.java similarity index 97% rename from java/lib/src/main/java/adf_core_python/gateway/Gateway.java rename to java/lib/src/main/java/adf_core_python/core/gateway/Gateway.java index 2e97b29..dc5c4c5 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/Gateway.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/Gateway.java @@ -1,4 +1,4 @@ -package adf_core_python.gateway; +package adf_core_python.core.gateway; import rescuecore2.registry.Registry; import rescuecore2.standard.entities.StandardEntityFactory; diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/AbstractMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/AbstractMapper.java similarity index 91% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/AbstractMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/AbstractMapper.java index 3a27ca9..4f95dfb 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/AbstractMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/AbstractMapper.java @@ -1,4 +1,4 @@ -package adf_core_python.gateway.mapper; +package adf_core_python.core.gateway.mapper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/MapperDict.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/MapperDict.java similarity index 63% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/MapperDict.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/MapperDict.java index 28e50f3..5cb4e16 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/MapperDict.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/MapperDict.java @@ -1,17 +1,17 @@ -package adf_core_python.gateway.mapper; - -import adf_core_python.component.module.AbstractModule; -import adf_core_python.component.module.algorithm.Clustering; -import adf_core_python.component.module.algorithm.DynamicClustering; -import adf_core_python.component.module.algorithm.PathPlanning; -import adf_core_python.component.module.algorithm.StaticClustering; -import adf_core_python.component.module.complex.*; -import adf_core_python.gateway.mapper.module.AbstractModuleMapper; -import adf_core_python.gateway.mapper.module.algorithm.ClusteringMapper; -import adf_core_python.gateway.mapper.module.algorithm.DynamicClusteringMapper; -import adf_core_python.gateway.mapper.module.algorithm.PathPlanningMapper; -import adf_core_python.gateway.mapper.module.algorithm.StaticClusteringMapper; -import adf_core_python.gateway.mapper.module.complex.*; +package adf_core_python.core.gateway.mapper; + +import adf_core_python.core.component.module.AbstractModule; +import adf_core_python.core.component.module.algorithm.Clustering; +import adf_core_python.core.component.module.algorithm.DynamicClustering; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import adf_core_python.core.component.module.algorithm.StaticClustering; +import adf_core_python.core.component.module.complex.*; +import adf_core_python.core.gateway.mapper.module.AbstractModuleMapper; +import adf_core_python.core.gateway.mapper.module.algorithm.ClusteringMapper; +import adf_core_python.core.gateway.mapper.module.algorithm.DynamicClusteringMapper; +import adf_core_python.core.gateway.mapper.module.algorithm.PathPlanningMapper; +import adf_core_python.core.gateway.mapper.module.algorithm.StaticClusteringMapper; +import adf_core_python.core.gateway.mapper.module.complex.*; import java.util.HashMap; diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/AbstractModuleMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/AbstractModuleMapper.java similarity index 84% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/AbstractModuleMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/AbstractModuleMapper.java index 984d801..0c66bad 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/AbstractModuleMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/AbstractModuleMapper.java @@ -1,9 +1,9 @@ -package adf_core_python.gateway.mapper.module; +package adf_core_python.core.gateway.mapper.module; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.AbstractModule; -import adf_core_python.gateway.mapper.AbstractMapper; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.AbstractModule; +import adf_core_python.core.gateway.mapper.AbstractMapper; import rescuecore2.config.Config; public class AbstractModuleMapper extends AbstractMapper { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/ClusteringMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/ClusteringMapper.java similarity index 94% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/ClusteringMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/ClusteringMapper.java index a063c20..0e57311 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/ClusteringMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/ClusteringMapper.java @@ -1,10 +1,10 @@ -package adf_core_python.gateway.mapper.module.algorithm; +package adf_core_python.core.gateway.mapper.module.algorithm; -import adf.core.agent.communication.MessageManager; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.algorithm.Clustering; -import adf_core_python.gateway.mapper.module.AbstractModuleMapper; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.Clustering; +import adf_core_python.core.gateway.mapper.module.AbstractModuleMapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import rescuecore2.config.Config; diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/DynamicClusteringMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/DynamicClusteringMapper.java similarity index 57% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/DynamicClusteringMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/DynamicClusteringMapper.java index 3dfdb43..bc60931 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/DynamicClusteringMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/DynamicClusteringMapper.java @@ -1,9 +1,9 @@ -package adf_core_python.gateway.mapper.module.algorithm; +package adf_core_python.core.gateway.mapper.module.algorithm; -import adf.core.agent.communication.MessageManager; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.algorithm.DynamicClustering; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.DynamicClustering; public class DynamicClusteringMapper extends ClusteringMapper { public DynamicClusteringMapper(DynamicClustering dynamicClustering, PrecomputeData precomputeData, MessageManager messageManager, WorldInfo worldInfo) { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/PathPlanningMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/PathPlanningMapper.java similarity index 92% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/PathPlanningMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/PathPlanningMapper.java index 335a642..00d6bfe 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/PathPlanningMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/PathPlanningMapper.java @@ -1,19 +1,19 @@ -package adf_core_python.gateway.mapper.module.algorithm; - -import java.util.Collection; -import java.util.List; +package adf_core_python.core.gateway.mapper.module.algorithm; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import adf_core_python.core.gateway.mapper.module.AbstractModuleMapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; - -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.algorithm.PathPlanning; -import adf_core_python.gateway.mapper.module.AbstractModuleMapper; import rescuecore2.config.Config; import rescuecore2.worldmodel.EntityID; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + public class PathPlanningMapper extends AbstractModuleMapper { public PathPlanningMapper(PathPlanning pathPlanning, PrecomputeData precomputeData, MessageManager messageManager) { super(pathPlanning, precomputeData, messageManager); @@ -34,7 +34,7 @@ public Config execMethod(String methodName, Config arguments) { try { targets = objectMapper.readValue(arguments.getValue("Targets"), new TypeReference>() { }); - } catch (JsonProcessingException e) { + } catch (IOException e) { throw new RuntimeException(e); } execSetDestination(targets); @@ -57,7 +57,7 @@ public Config execMethod(String methodName, Config arguments) { destinations = objectMapper.readValue(arguments.getValue("Destinations"), new TypeReference>() { }); - } catch (JsonProcessingException e) { + } catch (IOException e) { throw new RuntimeException(e); } result = execGetResult(new EntityID(arguments.getIntValue("From")), destinations); diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/StaticClusteringMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/StaticClusteringMapper.java similarity index 56% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/StaticClusteringMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/StaticClusteringMapper.java index daeaec3..16ec923 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/algorithm/StaticClusteringMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/algorithm/StaticClusteringMapper.java @@ -1,9 +1,9 @@ -package adf_core_python.gateway.mapper.module.algorithm; +package adf_core_python.core.gateway.mapper.module.algorithm; -import adf.core.agent.communication.MessageManager; import adf.core.agent.info.WorldInfo; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.algorithm.StaticClustering; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.StaticClustering; public class StaticClusteringMapper extends ClusteringMapper { public StaticClusteringMapper(StaticClustering staticClustering, PrecomputeData precomputeData, MessageManager messageManager, WorldInfo worldInfo) { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/AmbulanceTargetAllocatorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/AmbulanceTargetAllocatorMapper.java similarity index 58% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/AmbulanceTargetAllocatorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/AmbulanceTargetAllocatorMapper.java index e7beb49..4e5df45 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/AmbulanceTargetAllocatorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/AmbulanceTargetAllocatorMapper.java @@ -1,8 +1,8 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.AmbulanceTargetAllocator; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.AmbulanceTargetAllocator; public class AmbulanceTargetAllocatorMapper extends TargetAllocatorMapper { public AmbulanceTargetAllocatorMapper(AmbulanceTargetAllocator ambulanceTargetAllocator, PrecomputeData precomputeData, MessageManager messageManager) { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/BuildingDetectorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/BuildingDetectorMapper.java similarity index 56% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/BuildingDetectorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/BuildingDetectorMapper.java index 448dd1c..3a9bddd 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/BuildingDetectorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/BuildingDetectorMapper.java @@ -1,8 +1,8 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.BuildingDetector; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.BuildingDetector; public class BuildingDetectorMapper extends TargetDetectorMapper { public BuildingDetectorMapper(BuildingDetector buildingDetector, PrecomputeData precomputeData, MessageManager messageManager) { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/FireTargetAllocatorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/FireTargetAllocatorMapper.java similarity index 57% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/FireTargetAllocatorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/FireTargetAllocatorMapper.java index 235d3fa..6234471 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/FireTargetAllocatorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/FireTargetAllocatorMapper.java @@ -1,8 +1,8 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.FireTargetAllocator; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.FireTargetAllocator; public class FireTargetAllocatorMapper extends TargetAllocatorMapper { public FireTargetAllocatorMapper(FireTargetAllocator fireTargetAllocator, PrecomputeData precomputeData, MessageManager messageManager) { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/HumanDetectorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/HumanDetectorMapper.java similarity index 54% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/HumanDetectorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/HumanDetectorMapper.java index 2db6fed..078fe16 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/HumanDetectorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/HumanDetectorMapper.java @@ -1,8 +1,8 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.HumanDetector; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.HumanDetector; public class HumanDetectorMapper extends TargetDetectorMapper { public HumanDetectorMapper(HumanDetector humanDetector, PrecomputeData precomputeData, MessageManager messageManager) { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/PoliceTargetAllocatorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/PoliceTargetAllocatorMapper.java similarity index 57% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/PoliceTargetAllocatorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/PoliceTargetAllocatorMapper.java index 5092b72..1d6dd41 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/PoliceTargetAllocatorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/PoliceTargetAllocatorMapper.java @@ -1,8 +1,8 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.PoliceTargetAllocator; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.PoliceTargetAllocator; public class PoliceTargetAllocatorMapper extends TargetAllocatorMapper { public PoliceTargetAllocatorMapper(PoliceTargetAllocator policeTargetAllocator, PrecomputeData precomputeData, MessageManager messageManager) { diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/RoadDetectorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/RoadDetectorMapper.java similarity index 54% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/RoadDetectorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/RoadDetectorMapper.java index 4945c38..412634f 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/RoadDetectorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/RoadDetectorMapper.java @@ -1,8 +1,8 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.RoadDetector; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.RoadDetector; public class RoadDetectorMapper extends TargetDetectorMapper { public RoadDetectorMapper(RoadDetector roadDetector, PrecomputeData precomputeData, MessageManager messageManager) { diff --git a/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/SearchMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/SearchMapper.java new file mode 100644 index 0000000..7cf6d41 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/SearchMapper.java @@ -0,0 +1,11 @@ +package adf_core_python.core.gateway.mapper.module.complex; + +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.Search; + +public class SearchMapper extends TargetDetectorMapper { + public SearchMapper(Search search, PrecomputeData precomputeData, MessageManager messageManager) { + super(search, precomputeData, messageManager); + } +} diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/TargetAllocatorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/TargetAllocatorMapper.java similarity index 76% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/TargetAllocatorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/TargetAllocatorMapper.java index 78ba9d2..d211833 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/TargetAllocatorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/TargetAllocatorMapper.java @@ -1,9 +1,9 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.TargetAllocator; -import adf_core_python.gateway.mapper.module.AbstractModuleMapper; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.TargetAllocator; +import adf_core_python.core.gateway.mapper.module.AbstractModuleMapper; import rescuecore2.config.Config; import rescuecore2.worldmodel.EntityID; diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/TargetDetectorMapper.java b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/TargetDetectorMapper.java similarity index 76% rename from java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/TargetDetectorMapper.java rename to java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/TargetDetectorMapper.java index e0bb851..caaba9b 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/TargetDetectorMapper.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/mapper/module/complex/TargetDetectorMapper.java @@ -1,9 +1,9 @@ -package adf_core_python.gateway.mapper.module.complex; +package adf_core_python.core.gateway.mapper.module.complex; -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.TargetDetector; -import adf_core_python.gateway.mapper.module.AbstractModuleMapper; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.TargetDetector; +import adf_core_python.core.gateway.mapper.module.AbstractModuleMapper; import rescuecore2.config.Config; import rescuecore2.worldmodel.EntityID; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/AMAgent.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMAgent.java similarity index 91% rename from java/lib/src/main/java/adf_core_python/gateway/message/AMAgent.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/AMAgent.java index a7e34a5..17775b8 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/AMAgent.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMAgent.java @@ -1,7 +1,7 @@ -package adf_core_python.gateway.message; +package adf_core_python.core.gateway.message; -import adf_core_python.gateway.message.urn.ModuleMessageComponentURN; -import adf_core_python.gateway.message.urn.ModuleMessageURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageComponentURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageURN; import rescuecore2.config.Config; import rescuecore2.messages.AbstractMessage; import rescuecore2.messages.components.ConfigComponent; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/AMExec.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMExec.java similarity index 89% rename from java/lib/src/main/java/adf_core_python/gateway/message/AMExec.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/AMExec.java index 199f97d..5f6da2d 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/AMExec.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMExec.java @@ -1,7 +1,7 @@ -package adf_core_python.gateway.message; +package adf_core_python.core.gateway.message; -import adf_core_python.gateway.message.urn.ModuleMessageComponentURN; -import adf_core_python.gateway.message.urn.ModuleMessageURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageComponentURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageURN; import rescuecore2.config.Config; import rescuecore2.messages.AbstractMessage; import rescuecore2.messages.components.ConfigComponent; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/AMModule.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMModule.java similarity index 89% rename from java/lib/src/main/java/adf_core_python/gateway/message/AMModule.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/AMModule.java index a597897..10217ed 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/AMModule.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMModule.java @@ -1,7 +1,7 @@ -package adf_core_python.gateway.message; +package adf_core_python.core.gateway.message; -import adf_core_python.gateway.message.urn.ModuleMessageComponentURN; -import adf_core_python.gateway.message.urn.ModuleMessageURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageComponentURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageURN; import rescuecore2.messages.AbstractMessage; import rescuecore2.messages.components.StringComponent; import rescuecore2.messages.protobuf.RCRSProto; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/AMUpdate.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMUpdate.java similarity index 90% rename from java/lib/src/main/java/adf_core_python/gateway/message/AMUpdate.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/AMUpdate.java index ab3b03e..c3c21b5 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/AMUpdate.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/AMUpdate.java @@ -1,7 +1,7 @@ -package adf_core_python.gateway.message; +package adf_core_python.core.gateway.message; -import adf_core_python.gateway.message.urn.ModuleMessageComponentURN; -import adf_core_python.gateway.message.urn.ModuleMessageURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageComponentURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageURN; import rescuecore2.messages.AbstractMessage; import rescuecore2.messages.Command; import rescuecore2.messages.components.ChangeSetComponent; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/MAExecResponse.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/MAExecResponse.java similarity index 87% rename from java/lib/src/main/java/adf_core_python/gateway/message/MAExecResponse.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/MAExecResponse.java index e648838..ecd26df 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/MAExecResponse.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/MAExecResponse.java @@ -1,7 +1,7 @@ -package adf_core_python.gateway.message; +package adf_core_python.core.gateway.message; -import adf_core_python.gateway.message.urn.ModuleMessageComponentURN; -import adf_core_python.gateway.message.urn.ModuleMessageURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageComponentURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageURN; import rescuecore2.config.Config; import rescuecore2.messages.AbstractMessage; import rescuecore2.messages.components.ConfigComponent; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/MAModuleResponse.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/MAModuleResponse.java similarity index 87% rename from java/lib/src/main/java/adf_core_python/gateway/message/MAModuleResponse.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/MAModuleResponse.java index d568a61..bbd50d9 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/MAModuleResponse.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/MAModuleResponse.java @@ -1,7 +1,7 @@ -package adf_core_python.gateway.message; +package adf_core_python.core.gateway.message; -import adf_core_python.gateway.message.urn.ModuleMessageComponentURN; -import adf_core_python.gateway.message.urn.ModuleMessageURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageComponentURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageURN; import rescuecore2.messages.AbstractMessage; import rescuecore2.messages.components.StringComponent; import rescuecore2.messages.protobuf.RCRSProto; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/ModuleControlMessageFactory.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/ModuleControlMessageFactory.java similarity index 93% rename from java/lib/src/main/java/adf_core_python/gateway/message/ModuleControlMessageFactory.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/ModuleControlMessageFactory.java index 3952131..c6b4ac7 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/ModuleControlMessageFactory.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/ModuleControlMessageFactory.java @@ -1,6 +1,6 @@ -package adf_core_python.gateway.message; +package adf_core_python.core.gateway.message; -import adf_core_python.gateway.message.urn.ModuleMessageURN; +import adf_core_python.core.gateway.message.urn.ModuleMessageURN; import rescuecore2.messages.Message; import rescuecore2.messages.protobuf.RCRSProto.MessageProto; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/urn/ModuleMessageComponentURN.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/urn/ModuleMessageComponentURN.java similarity index 96% rename from java/lib/src/main/java/adf_core_python/gateway/message/urn/ModuleMessageComponentURN.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/urn/ModuleMessageComponentURN.java index 868439c..c89232d 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/urn/ModuleMessageComponentURN.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/urn/ModuleMessageComponentURN.java @@ -1,4 +1,4 @@ -package adf_core_python.gateway.message.urn; +package adf_core_python.core.gateway.message.urn; import rescuecore2.URN; diff --git a/java/lib/src/main/java/adf_core_python/gateway/message/urn/ModuleMessageURN.java b/java/lib/src/main/java/adf_core_python/core/gateway/message/urn/ModuleMessageURN.java similarity index 96% rename from java/lib/src/main/java/adf_core_python/gateway/message/urn/ModuleMessageURN.java rename to java/lib/src/main/java/adf_core_python/core/gateway/message/urn/ModuleMessageURN.java index 8c90a4e..83358b5 100644 --- a/java/lib/src/main/java/adf_core_python/gateway/message/urn/ModuleMessageURN.java +++ b/java/lib/src/main/java/adf_core_python/core/gateway/message/urn/ModuleMessageURN.java @@ -1,4 +1,4 @@ -package adf_core_python.gateway.message.urn; +package adf_core_python.core.gateway.message.urn; import rescuecore2.URN; diff --git a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/SearchMapper.java b/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/SearchMapper.java deleted file mode 100644 index 94f42db..0000000 --- a/java/lib/src/main/java/adf_core_python/gateway/mapper/module/complex/SearchMapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package adf_core_python.gateway.mapper.module.complex; - -import adf.core.agent.communication.MessageManager; -import adf_core_python.agent.precompute.PrecomputeData; -import adf_core_python.component.module.complex.Search; - -public class SearchMapper extends TargetDetectorMapper { - public SearchMapper(Search search, PrecomputeData precomputeData, MessageManager messageManager) { - super(search, precomputeData, messageManager); - } -} diff --git a/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionClear.java b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionClear.java new file mode 100644 index 0000000..bb415cb --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionClear.java @@ -0,0 +1,803 @@ +package adf_core_python.impl.extaction; + +import adf.core.agent.action.Action; +import adf.core.agent.action.common.ActionMove; +import adf.core.agent.action.common.ActionRest; +import adf.core.agent.action.police.ActionClear; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.extaction.ExtAction; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import com.google.common.collect.Lists; +import rescuecore2.config.NoSuchConfigOptionException; +import rescuecore2.misc.geometry.GeometryTools2D; +import rescuecore2.misc.geometry.Line2D; +import rescuecore2.misc.geometry.Point2D; +import rescuecore2.misc.geometry.Vector2D; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; +import java.util.stream.Collectors; + +public class DefaultExtActionClear extends ExtAction { + + private PathPlanning pathPlanning; + + private int clearDistance; + private int forcedMove; + private int thresholdRest; + private int kernelTime; + + private EntityID target; + private Map> movePointCache; + private int oldClearX; + private int oldClearY; + private int count; + + public DefaultExtActionClear(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.clearDistance = si.getClearRepairDistance(); + this.forcedMove = developData + .getInteger("adf.impl.extaction.DefaultExtActionClear.forcedMove", 3); + this.thresholdRest = developData + .getInteger("adf.impl.extaction.DefaultExtActionClear.rest", 100); + + this.target = null; + this.movePointCache = new HashMap<>(); + this.oldClearX = 0; + this.oldClearY = 0; + this.count = 0; + + switch (si.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.pathPlanning = moduleManager.getModule( + "DefaultExtActionClear.PathPlanning", + "adf_core_python.impl.module.algorithm.DijkstraPathPlanning"); + break; + } + } + + + @Override + public ExtAction precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + this.pathPlanning.precompute(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.pathPlanning.resume(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.pathPlanning.preparate(); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + this.pathPlanning.updateInfo(messageManager); + return this; + } + + + @Override + public ExtAction setTarget(EntityID target) { + this.target = null; + StandardEntity entity = this.worldInfo.getEntity(target); + if (entity != null) { + if (entity instanceof Road) { + this.target = target; + } else if (entity.getStandardURN().equals(StandardEntityURN.BLOCKADE)) { + this.target = ((Blockade) entity).getPosition(); + } else if (entity instanceof Building) { + this.target = target; + } + } + return this; + } + + + @Override + public ExtAction calc() { + this.result = null; + PoliceForce policeForce = (PoliceForce) this.agentInfo.me(); + + if (this.needRest(policeForce)) { + List list = new ArrayList<>(); + if (this.target != null) { + list.add(this.target); + } + this.result = this.calcRest(policeForce, this.pathPlanning, list); + if (this.result != null) { + return this; + } + } + + if (this.target == null) { + return this; + } + EntityID agentPosition = policeForce.getPosition(); + StandardEntity targetEntity = this.worldInfo.getEntity(this.target); + StandardEntity positionEntity = Objects + .requireNonNull(this.worldInfo.getEntity(agentPosition)); + if (targetEntity == null || !(targetEntity instanceof Area)) { + return this; + } + if (positionEntity instanceof Road) { + this.result = this.getRescueAction(policeForce, (Road) positionEntity); + if (this.result != null) { + return this; + } + } + if (agentPosition.equals(this.target)) { + this.result = this.getAreaClearAction(policeForce, targetEntity); + } else if (((Area) targetEntity).getEdgeTo(agentPosition) != null) { + this.result = this.getNeighbourPositionAction(policeForce, + (Area) targetEntity); + } else { + List path = this.pathPlanning.getResult(agentPosition, + this.target); + if (path != null && path.size() > 0) { + int index = path.indexOf(agentPosition); + if (index == -1) { + Area area = (Area) positionEntity; + for (int i = 0; i < path.size(); i++) { + if (area.getEdgeTo(path.get(i)) != null) { + index = i; + break; + } + } + } else if (index >= 0) { + index++; + } + if (index >= 0 && index < (path.size())) { + StandardEntity entity = this.worldInfo.getEntity(path.get(index)); + this.result = this.getNeighbourPositionAction(policeForce, + (Area) entity); + if (this.result != null + && this.result.getClass() == ActionMove.class) { + if (!((ActionMove) this.result).getUsePosition()) { + this.result = null; + } + } + } + if (this.result == null) { + this.result = new ActionMove(path); + } + } + } + return this; + } + + + private Action getRescueAction(PoliceForce police, Road road) { + if (!road.isBlockadesDefined()) { + return null; + } + Collection blockades = this.worldInfo.getBlockades(road).stream() + .filter(Blockade::isApexesDefined).collect(Collectors.toSet()); + Collection agents = this.worldInfo.getEntitiesOfType( + StandardEntityURN.AMBULANCE_TEAM, StandardEntityURN.FIRE_BRIGADE); + + double policeX = police.getX(); + double policeY = police.getY(); + double minDistance = Double.MAX_VALUE; + Action moveAction = null; + for (StandardEntity entity : agents) { + Human human = (Human) entity; + if (!human.isPositionDefined() + || human.getPosition().getValue() != road.getID().getValue()) { + continue; + } + double humanX = human.getX(); + double humanY = human.getY(); + ActionClear actionClear = null; + for (Blockade blockade : blockades) { + if (!this.isInside(humanX, humanY, blockade.getApexes())) { + continue; + } + double distance = this.getDistance(policeX, policeY, humanX, humanY); + if (this.intersect(policeX, policeY, humanX, humanY, road)) { + Action action = this.getIntersectEdgeAction(policeX, policeY, humanX, + humanY, road); + if (action == null) { + continue; + } + if (action.getClass() == ActionClear.class) { + if (actionClear == null) { + actionClear = (ActionClear) action; + continue; + } + if (actionClear.getTarget() != null) { + Blockade another = (Blockade) this.worldInfo + .getEntity(actionClear.getTarget()); + if (another != null && this.intersect(blockade, another)) { + return new ActionClear(another); + } + int anotherDistance = this.worldInfo.getDistance(police, another); + int blockadeDistance = this.worldInfo.getDistance(police, + blockade); + if (anotherDistance > blockadeDistance) { + return action; + } + } + return actionClear; + } else if (action.getClass() == ActionMove.class + && distance < minDistance) { + minDistance = distance; + moveAction = action; + } + } else if (this.intersect(policeX, policeY, humanX, humanY, blockade)) { + Vector2D vector = this + .scaleClear(this.getVector(policeX, policeY, humanX, humanY)); + int clearX = (int) (policeX + vector.getX()); + int clearY = (int) (policeY + vector.getY()); + vector = this.scaleBackClear(vector); + int startX = (int) (policeX + vector.getX()); + int startY = (int) (policeY + vector.getY()); + if (this.intersect(startX, startY, clearX, clearY, blockade)) { + if (actionClear == null) { + actionClear = new ActionClear(clearX, clearY, blockade); + } else { + if (actionClear.getTarget() != null) { + Blockade another = (Blockade) this.worldInfo + .getEntity(actionClear.getTarget()); + if (another != null && this.intersect(blockade, another)) { + return new ActionClear(another); + } + int distance1 = this.worldInfo.getDistance(police, another); + int distance2 = this.worldInfo.getDistance(police, blockade); + if (distance1 > distance2) { + return new ActionClear(clearX, clearY, blockade); + } + } + return actionClear; + } + } else if (distance < minDistance) { + minDistance = distance; + moveAction = new ActionMove(Lists.newArrayList(road.getID()), + (int) humanX, (int) humanY); + } + } + } + if (actionClear != null) { + return actionClear; + } + } + return moveAction; + } + + + private Action getAreaClearAction(PoliceForce police, + StandardEntity targetEntity) { + if (targetEntity instanceof Building) { + return null; + } + Road road = (Road) targetEntity; + if (!road.isBlockadesDefined() || road.getBlockades().isEmpty()) { + return null; + } + Collection blockades = this.worldInfo.getBlockades(road).stream() + .filter(Blockade::isApexesDefined).collect(Collectors.toSet()); + int minDistance = Integer.MAX_VALUE; + Blockade clearBlockade = null; + for (Blockade blockade : blockades) { + for (Blockade another : blockades) { + if (!blockade.getID().equals(another.getID()) + && this.intersect(blockade, another)) { + int distance1 = this.worldInfo.getDistance(police, blockade); + int distance2 = this.worldInfo.getDistance(police, another); + if (distance1 <= distance2 && distance1 < minDistance) { + minDistance = distance1; + clearBlockade = blockade; + } else if (distance2 < minDistance) { + minDistance = distance2; + clearBlockade = another; + } + } + } + } + if (clearBlockade != null) { + if (minDistance < this.clearDistance) { + return new ActionClear(clearBlockade); + } else { + return new ActionMove(Lists.newArrayList(police.getPosition()), + clearBlockade.getX(), clearBlockade.getY()); + } + } + double agentX = police.getX(); + double agentY = police.getY(); + clearBlockade = null; + Double minPointDistance = Double.MAX_VALUE; + int clearX = 0; + int clearY = 0; + for (Blockade blockade : blockades) { + int[] apexes = blockade.getApexes(); + for (int i = 0; i < (apexes.length - 2); i += 2) { + double distance = this.getDistance(agentX, agentY, apexes[i], + apexes[i + 1]); + if (distance < minPointDistance) { + clearBlockade = blockade; + minPointDistance = distance; + clearX = apexes[i]; + clearY = apexes[i + 1]; + } + } + } + if (clearBlockade != null) { + if (minPointDistance < this.clearDistance) { + Vector2D vector = this + .scaleClear(this.getVector(agentX, agentY, clearX, clearY)); + clearX = (int) (agentX + vector.getX()); + clearY = (int) (agentY + vector.getY()); + return new ActionClear(clearX, clearY, clearBlockade); + } + return new ActionMove(Lists.newArrayList(police.getPosition()), clearX, + clearY); + } + return null; + } + + + private Action getNeighbourPositionAction(PoliceForce police, Area target) { + double agentX = police.getX(); + double agentY = police.getY(); + StandardEntity position = Objects + .requireNonNull(this.worldInfo.getPosition(police)); + Edge edge = target.getEdgeTo(position.getID()); + if (edge == null) { + return null; + } + if (position instanceof Road) { + Road road = (Road) position; + if (road.isBlockadesDefined() && road.getBlockades().size() > 0) { + double midX = (edge.getStartX() + edge.getEndX()) / 2; + double midY = (edge.getStartY() + edge.getEndY()) / 2; + if (this.intersect(agentX, agentY, midX, midY, road)) { + return this.getIntersectEdgeAction(agentX, agentY, edge, road); + } + ActionClear actionClear = null; + ActionMove actionMove = null; + Vector2D vector = this + .scaleClear(this.getVector(agentX, agentY, midX, midY)); + int clearX = (int) (agentX + vector.getX()); + int clearY = (int) (agentY + vector.getY()); + vector = this.scaleBackClear(vector); + int startX = (int) (agentX + vector.getX()); + int startY = (int) (agentY + vector.getY()); + for (Blockade blockade : this.worldInfo.getBlockades(road)) { + if (blockade == null || !blockade.isApexesDefined()) { + continue; + } + if (this.intersect(startX, startY, midX, midY, blockade)) { + if (this.intersect(startX, startY, clearX, clearY, blockade)) { + if (actionClear == null) { + actionClear = new ActionClear(clearX, clearY, blockade); + if (this.equalsPoint(this.oldClearX, this.oldClearY, clearX, + clearY)) { + if (this.count >= this.forcedMove) { + this.count = 0; + return new ActionMove(Lists.newArrayList(road.getID()), + clearX, clearY); + } + this.count++; + } + this.oldClearX = clearX; + this.oldClearY = clearY; + } else { + if (actionClear.getTarget() != null) { + Blockade another = (Blockade) this.worldInfo + .getEntity(actionClear.getTarget()); + if (another != null && this.intersect(blockade, another)) { + return new ActionClear(another); + } + } + return actionClear; + } + } else if (actionMove == null) { + actionMove = new ActionMove(Lists.newArrayList(road.getID()), + (int) midX, (int) midY); + } + } + } + if (actionClear != null) { + return actionClear; + } else if (actionMove != null) { + return actionMove; + } + } + } + if (target instanceof Road) { + Road road = (Road) target; + if (!road.isBlockadesDefined() || road.getBlockades().isEmpty()) { + return new ActionMove( + Lists.newArrayList(position.getID(), target.getID())); + } + Blockade clearBlockade = null; + Double minPointDistance = Double.MAX_VALUE; + int clearX = 0; + int clearY = 0; + for (EntityID id : road.getBlockades()) { + Blockade blockade = (Blockade) this.worldInfo.getEntity(id); + if (blockade != null && blockade.isApexesDefined()) { + int[] apexes = blockade.getApexes(); + for (int i = 0; i < (apexes.length - 2); i += 2) { + double distance = this.getDistance(agentX, agentY, apexes[i], + apexes[i + 1]); + if (distance < minPointDistance) { + clearBlockade = blockade; + minPointDistance = distance; + clearX = apexes[i]; + clearY = apexes[i + 1]; + } + } + } + } + if (clearBlockade != null && minPointDistance < this.clearDistance) { + Vector2D vector = this + .scaleClear(this.getVector(agentX, agentY, clearX, clearY)); + clearX = (int) (agentX + vector.getX()); + clearY = (int) (agentY + vector.getY()); + if (this.equalsPoint(this.oldClearX, this.oldClearY, clearX, clearY)) { + if (this.count >= this.forcedMove) { + this.count = 0; + return new ActionMove(Lists.newArrayList(road.getID()), clearX, + clearY); + } + this.count++; + } + this.oldClearX = clearX; + this.oldClearY = clearY; + return new ActionClear(clearX, clearY, clearBlockade); + } + } + return new ActionMove(Lists.newArrayList(position.getID(), target.getID())); + } + + + private Action getIntersectEdgeAction(double agentX, double agentY, Edge edge, + Road road) { + double midX = (edge.getStartX() + edge.getEndX()) / 2; + double midY = (edge.getStartY() + edge.getEndY()) / 2; + return this.getIntersectEdgeAction(agentX, agentY, midX, midY, road); + } + + + private Action getIntersectEdgeAction(double agentX, double agentY, + double pointX, double pointY, Road road) { + Set movePoints = this.getMovePoints(road); + Point2D bestPoint = null; + double bastDistance = Double.MAX_VALUE; + for (Point2D p : movePoints) { + if (!this.intersect(agentX, agentY, p.getX(), p.getY(), road)) { + if (!this.intersect(pointX, pointY, p.getX(), p.getY(), road)) { + double distance = this.getDistance(pointX, pointY, p.getX(), + p.getY()); + if (distance < bastDistance) { + bestPoint = p; + bastDistance = distance; + } + } + } + } + if (bestPoint != null) { + double pX = bestPoint.getX(); + double pY = bestPoint.getY(); + if (!road.isBlockadesDefined()) { + return new ActionMove(Lists.newArrayList(road.getID()), (int) pX, + (int) pY); + } + ActionClear actionClear = null; + ActionMove actionMove = null; + Vector2D vector = this.scaleClear(this.getVector(agentX, agentY, pX, pY)); + int clearX = (int) (agentX + vector.getX()); + int clearY = (int) (agentY + vector.getY()); + vector = this.scaleBackClear(vector); + int startX = (int) (agentX + vector.getX()); + int startY = (int) (agentY + vector.getY()); + for (Blockade blockade : this.worldInfo.getBlockades(road)) { + if (this.intersect(startX, startY, pX, pY, blockade)) { + if (this.intersect(startX, startY, clearX, clearY, blockade)) { + if (actionClear == null) { + actionClear = new ActionClear(clearX, clearY, blockade); + } else { + if (actionClear.getTarget() != null) { + Blockade another = (Blockade) this.worldInfo + .getEntity(actionClear.getTarget()); + if (another != null && this.intersect(blockade, another)) { + return new ActionClear(another); + } + } + return actionClear; + } + } else if (actionMove == null) { + actionMove = new ActionMove(Lists.newArrayList(road.getID()), + (int) pX, (int) pY); + } + } + } + if (actionClear != null) { + return actionClear; + } else if (actionMove != null) { + return actionMove; + } + } + Action action = this.getAreaClearAction((PoliceForce) this.agentInfo.me(), + road); + if (action == null) { + action = new ActionMove(Lists.newArrayList(road.getID()), (int) pointX, + (int) pointY); + } + return action; + } + + + private boolean equalsPoint(double p1X, double p1Y, double p2X, double p2Y) { + return this.equalsPoint(p1X, p1Y, p2X, p2Y, 1000.0D); + } + + + private boolean equalsPoint(double p1X, double p1Y, double p2X, double p2Y, + double range) { + return (p2X - range < p1X && p1X < p2X + range) + && (p2Y - range < p1Y && p1Y < p2Y + range); + } + + + private boolean isInside(double pX, double pY, int[] apex) { + Point2D p = new Point2D(pX, pY); + Vector2D v1 = (new Point2D(apex[apex.length - 2], apex[apex.length - 1])) + .minus(p); + Vector2D v2 = (new Point2D(apex[0], apex[1])).minus(p); + double theta = this.getAngle(v1, v2); + + for (int i = 0; i < apex.length - 2; i += 2) { + v1 = (new Point2D(apex[i], apex[i + 1])).minus(p); + v2 = (new Point2D(apex[i + 2], apex[i + 3])).minus(p); + theta += this.getAngle(v1, v2); + } + return Math.round(Math.abs((theta / 2) / Math.PI)) >= 1; + } + + + private boolean intersect(double agentX, double agentY, double pointX, + double pointY, Area area) { + for (Edge edge : area.getEdges()) { + double startX = edge.getStartX(); + double startY = edge.getStartY(); + double endX = edge.getEndX(); + double endY = edge.getEndY(); + if (java.awt.geom.Line2D.linesIntersect(agentX, agentY, pointX, pointY, + startX, startY, endX, endY)) { + double midX = (edge.getStartX() + edge.getEndX()) / 2; + double midY = (edge.getStartY() + edge.getEndY()) / 2; + if (!equalsPoint(pointX, pointY, midX, midY) + && !equalsPoint(agentX, agentY, midX, midY)) { + return true; + } + } + } + return false; + } + + + private boolean intersect(Blockade blockade, Blockade another) { + if (blockade.isApexesDefined() && another.isApexesDefined()) { + int[] apexes0 = blockade.getApexes(); + int[] apexes1 = another.getApexes(); + for (int i = 0; i < (apexes0.length - 2); i += 2) { + for (int j = 0; j < (apexes1.length - 2); j += 2) { + if (java.awt.geom.Line2D.linesIntersect(apexes0[i], apexes0[i + 1], + apexes0[i + 2], apexes0[i + 3], apexes1[j], apexes1[j + 1], + apexes1[j + 2], apexes1[j + 3])) { + return true; + } + } + } + for (int i = 0; i < (apexes0.length - 2); i += 2) { + if (java.awt.geom.Line2D.linesIntersect(apexes0[i], apexes0[i + 1], + apexes0[i + 2], apexes0[i + 3], apexes1[apexes1.length - 2], + apexes1[apexes1.length - 1], apexes1[0], apexes1[1])) { + return true; + } + } + for (int j = 0; j < (apexes1.length - 2); j += 2) { + if (java.awt.geom.Line2D.linesIntersect(apexes0[apexes0.length - 2], + apexes0[apexes0.length - 1], apexes0[0], apexes0[1], apexes1[j], + apexes1[j + 1], apexes1[j + 2], apexes1[j + 3])) { + return true; + } + } + } + return false; + } + + + private boolean intersect(double agentX, double agentY, double pointX, + double pointY, Blockade blockade) { + List lines = GeometryTools2D.pointsToLines( + GeometryTools2D.vertexArrayToPoints(blockade.getApexes()), true); + for (Line2D line : lines) { + Point2D start = line.getOrigin(); + Point2D end = line.getEndPoint(); + double startX = start.getX(); + double startY = start.getY(); + double endX = end.getX(); + double endY = end.getY(); + if (java.awt.geom.Line2D.linesIntersect(agentX, agentY, pointX, pointY, + startX, startY, endX, endY)) { + return true; + } + } + return false; + } + + + private double getDistance(double fromX, double fromY, double toX, + double toY) { + double dx = toX - fromX; + double dy = toY - fromY; + return Math.hypot(dx, dy); + } + + + private double getAngle(Vector2D v1, Vector2D v2) { + double flag = (v1.getX() * v2.getY()) - (v1.getY() * v2.getX()); + double angle = Math.acos(((v1.getX() * v2.getX()) + (v1.getY() * v2.getY())) + / (v1.getLength() * v2.getLength())); + if (flag > 0) { + return angle; + } + if (flag < 0) { + return -1 * angle; + } + return 0.0D; + } + + + private Vector2D getVector(double fromX, double fromY, double toX, + double toY) { + return (new Point2D(toX, toY)).minus(new Point2D(fromX, fromY)); + } + + + private Vector2D scaleClear(Vector2D vector) { + return vector.normalised().scale(this.clearDistance); + } + + + private Vector2D scaleBackClear(Vector2D vector) { + return vector.normalised().scale(-510); + } + + + private Set getMovePoints(Road road) { + Set points = this.movePointCache.get(road.getID()); + if (points == null) { + points = new HashSet<>(); + int[] apex = road.getApexList(); + for (int i = 0; i < apex.length; i += 2) { + for (int j = i + 2; j < apex.length; j += 2) { + double midX = (apex[i] + apex[j]) / 2; + double midY = (apex[i + 1] + apex[j + 1]) / 2; + if (this.isInside(midX, midY, apex)) { + points.add(new Point2D(midX, midY)); + } + } + } + for (Edge edge : road.getEdges()) { + double midX = (edge.getStartX() + edge.getEndX()) / 2; + double midY = (edge.getStartY() + edge.getEndY()) / 2; + points.remove(new Point2D(midX, midY)); + } + this.movePointCache.put(road.getID(), points); + } + return points; + } + + + private boolean needRest(Human agent) { + int hp = agent.getHP(); + int damage = agent.getDamage(); + if (damage == 0 || hp == 0) { + return false; + } + int activeTime = (hp / damage) + ((hp % damage) != 0 ? 1 : 0); + if (this.kernelTime == -1) { + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + } + return damage >= this.thresholdRest + || (activeTime + this.agentInfo.getTime()) < this.kernelTime; + } + + + private Action calcRest(Human human, PathPlanning pathPlanning, + Collection targets) { + EntityID position = human.getPosition(); + Collection refuges = this.worldInfo + .getEntityIDsOfType(StandardEntityURN.REFUGE); + int currentSize = refuges.size(); + if (refuges.contains(position)) { + return new ActionRest(); + } + List firstResult = null; + while (refuges.size() > 0) { + pathPlanning.setFrom(position); + pathPlanning.setDestination(refuges); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + if (firstResult == null) { + firstResult = new ArrayList<>(path); + if (targets == null || targets.isEmpty()) { + break; + } + } + EntityID refugeID = path.get(path.size() - 1); + pathPlanning.setFrom(refugeID); + pathPlanning.setDestination(targets); + List fromRefugeToTarget = pathPlanning.calc().getResult(); + if (fromRefugeToTarget != null && fromRefugeToTarget.size() > 0) { + return new ActionMove(path); + } + refuges.remove(refugeID); + // remove failed + if (currentSize == refuges.size()) { + break; + } + currentSize = refuges.size(); + } else { + break; + } + } + return firstResult != null ? new ActionMove(firstResult) : null; + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionFireFighting.java b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionFireFighting.java new file mode 100644 index 0000000..f5ae30c --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionFireFighting.java @@ -0,0 +1,351 @@ +package adf_core_python_core_python.impl.extaction; + +import adf.core.agent.action.Action; +import adf.core.agent.action.common.ActionMove; +import adf.core.agent.action.common.ActionRest; +import adf.core.agent.action.fire.ActionExtinguish; +import adf.core.agent.action.fire.ActionRefill; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.extaction.ExtAction; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import rescuecore2.config.NoSuchConfigOptionException; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +import static rescuecore2.standard.entities.StandardEntityURN.HYDRANT; +import static rescuecore2.standard.entities.StandardEntityURN.REFUGE; + +public class DefaultExtActionFireFighting extends ExtAction { + + private PathPlanning pathPlanning; + + private int maxExtinguishDistance; + private int maxExtinguishPower; + private int thresholdRest; + private int kernelTime; + private int refillCompleted; + private int refillRequest; + private boolean refillFlag; + + private EntityID target; + + public DefaultExtActionFireFighting(AgentInfo agentInfo, WorldInfo worldInfo, ScenarioInfo scenarioInfo, ModuleManager moduleManager, DevelopData developData) { + super(agentInfo, worldInfo, scenarioInfo, moduleManager, developData); + this.maxExtinguishDistance = scenarioInfo.getFireExtinguishMaxDistance(); + this.maxExtinguishPower = scenarioInfo.getFireExtinguishMaxSum(); + this.thresholdRest = developData.getInteger( + "adf.impl.extaction.DefaultExtActionFireFighting.rest", 100); + int maxWater = scenarioInfo.getFireTankMaximum(); + this.refillCompleted = (maxWater / 10) * developData.getInteger( + "adf.impl.extaction.DefaultExtActionFireFighting.refill.completed", 10); + this.refillRequest = this.maxExtinguishPower * developData.getInteger( + "adf.impl.extaction.DefaultExtActionFireFighting.refill.request", 1); + this.refillFlag = false; + + this.target = null; + + switch (scenarioInfo.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.pathPlanning = moduleManager.getModule( + "DefaultExtActionFireFighting.PathPlanning", + "adf_core_python.impl.module.algorithm.DijkstraPathPlanning"); + break; + } + } + + + @Override + public ExtAction precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + this.pathPlanning.precompute(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.pathPlanning.resume(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.pathPlanning.preparate(); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + this.pathPlanning.updateInfo(messageManager); + return this; + } + + + @Override + public ExtAction setTarget(EntityID target) { + this.target = null; + if (target != null) { + StandardEntity entity = this.worldInfo.getEntity(target); + if (entity instanceof Building) { + this.target = target; + } + } + return this; + } + + + @Override + public ExtAction calc() { + this.result = null; + FireBrigade agent = (FireBrigade) this.agentInfo.me(); + + this.refillFlag = this.needRefill(agent, this.refillFlag); + if (this.refillFlag) { + this.result = this.calcRefill(agent, this.pathPlanning, this.target); + if (this.result != null) { + return this; + } + } + + if (this.needRest(agent)) { + this.result = this.calcRefugeAction(agent, this.pathPlanning, this.target, + false); + if (this.result != null) { + return this; + } + } + + if (this.target == null) { + return this; + } + this.result = this.calcExtinguish(agent, this.pathPlanning, this.target); + return this; + } + + + private Action calcExtinguish(FireBrigade agent, PathPlanning pathPlanning, + EntityID target) { + EntityID agentPosition = agent.getPosition(); + StandardEntity positionEntity = Objects + .requireNonNull(this.worldInfo.getPosition(agent)); + if (StandardEntityURN.REFUGE == positionEntity.getStandardURN()) { + Action action = this.getMoveAction(pathPlanning, agentPosition, target); + if (action != null) { + return action; + } + } + + List neighbourBuilding = new ArrayList<>(); + StandardEntity entity = this.worldInfo.getEntity(target); + if (entity instanceof Building) { + if (this.worldInfo.getDistance(positionEntity, + entity) < this.maxExtinguishDistance) { + neighbourBuilding.add(entity); + } + } + + if (neighbourBuilding.size() > 0) { + neighbourBuilding.sort(new DistanceSorter(this.worldInfo, agent)); + return new ActionExtinguish(neighbourBuilding.get(0).getID(), + this.maxExtinguishPower); + } + return this.getMoveAction(pathPlanning, agentPosition, target); + } + + + private Action getMoveAction(PathPlanning pathPlanning, EntityID from, + EntityID target) { + pathPlanning.setFrom(from); + pathPlanning.setDestination(target); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + StandardEntity entity = this.worldInfo + .getEntity(path.get(path.size() - 1)); + if (entity instanceof Building) { + if (entity.getStandardURN() != StandardEntityURN.REFUGE) { + path.remove(path.size() - 1); + } + } + return new ActionMove(path); + } + return null; + } + + + private boolean needRefill(FireBrigade agent, boolean refillFlag) { + if (refillFlag) { + StandardEntityURN positionURN = Objects + .requireNonNull(this.worldInfo.getPosition(agent)).getStandardURN(); + return !(positionURN == REFUGE || positionURN == HYDRANT) + || agent.getWater() < this.refillCompleted; + } + return agent.getWater() <= this.refillRequest; + } + + + private boolean needRest(Human agent) { + int hp = agent.getHP(); + int damage = agent.getDamage(); + if (hp == 0 || damage == 0) { + return false; + } + int activeTime = (hp / damage) + ((hp % damage) != 0 ? 1 : 0); + if (this.kernelTime == -1) { + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + } + return damage >= this.thresholdRest + || (activeTime + this.agentInfo.getTime()) < this.kernelTime; + } + + + private Action calcRefill(FireBrigade agent, PathPlanning pathPlanning, + EntityID target) { + StandardEntityURN positionURN = Objects + .requireNonNull(this.worldInfo.getPosition(agent)).getStandardURN(); + if (positionURN == REFUGE) { + return new ActionRefill(); + } + Action action = this.calcRefugeAction(agent, pathPlanning, target, true); + if (action != null) { + return action; + } + action = this.calcHydrantAction(agent, pathPlanning, target); + if (action != null) { + if (positionURN == HYDRANT + && action.getClass().equals(ActionMove.class)) { + pathPlanning.setFrom(agent.getPosition()); + pathPlanning.setDestination(target); + double currentDistance = pathPlanning.calc().getDistance(); + List path = ((ActionMove) action).getPath(); + pathPlanning.setFrom(path.get(path.size() - 1)); + pathPlanning.setDestination(target); + double newHydrantDistance = pathPlanning.calc().getDistance(); + if (currentDistance <= newHydrantDistance) { + return new ActionRefill(); + } + } + return action; + } + return null; + } + + + private Action calcRefugeAction(Human human, PathPlanning pathPlanning, + EntityID target, boolean isRefill) { + return this.calcSupplyAction(human, pathPlanning, + this.worldInfo.getEntityIDsOfType(StandardEntityURN.REFUGE), target, + isRefill); + } + + + private Action calcHydrantAction(Human human, PathPlanning pathPlanning, + EntityID target) { + Collection hydrants = this.worldInfo.getEntityIDsOfType(HYDRANT); + hydrants.remove(human.getPosition()); + return this.calcSupplyAction(human, pathPlanning, hydrants, target, true); + } + + + private Action calcSupplyAction(Human human, PathPlanning pathPlanning, + Collection supplyPositions, EntityID target, boolean isRefill) { + EntityID position = human.getPosition(); + int size = supplyPositions.size(); + if (supplyPositions.contains(position)) { + return isRefill ? new ActionRefill() : new ActionRest(); + } + List firstResult = null; + while (supplyPositions.size() > 0) { + pathPlanning.setFrom(position); + pathPlanning.setDestination(supplyPositions); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + if (firstResult == null) { + firstResult = new ArrayList<>(path); + if (target == null) { + break; + } + } + EntityID supplyPositionID = path.get(path.size() - 1); + pathPlanning.setFrom(supplyPositionID); + pathPlanning.setDestination(target); + List fromRefugeToTarget = pathPlanning.calc().getResult(); + if (fromRefugeToTarget != null && fromRefugeToTarget.size() > 0) { + return new ActionMove(path); + } + supplyPositions.remove(supplyPositionID); + // remove failed + if (size == supplyPositions.size()) { + break; + } + size = supplyPositions.size(); + } else { + break; + } + } + return firstResult != null ? new ActionMove(firstResult) : null; + } + + private class DistanceSorter implements Comparator { + + private StandardEntity reference; + private WorldInfo worldInfo; + + DistanceSorter(WorldInfo wi, StandardEntity reference) { + this.reference = reference; + this.worldInfo = wi; + } + + + public int compare(StandardEntity a, StandardEntity b) { + int d1 = this.worldInfo.getDistance(this.reference, a); + int d2 = this.worldInfo.getDistance(this.reference, b); + return d1 - d2; + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionFireRescue.java b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionFireRescue.java new file mode 100644 index 0000000..05f4bb7 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionFireRescue.java @@ -0,0 +1,227 @@ +package adf_core_python.impl.extaction; + +import adf.core.agent.action.Action; +import adf.core.agent.action.ambulance.ActionRescue; +import adf.core.agent.action.common.ActionMove; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.extaction.ExtAction; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import rescuecore2.config.NoSuchConfigOptionException; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.ArrayList; +import java.util.List; + +import static rescuecore2.standard.entities.StandardEntityURN.BLOCKADE; + +public class DefaultExtActionFireRescue extends ExtAction { + + private PathPlanning pathPlanning; + + private int thresholdRest; + private int kernelTime; + + private EntityID target; + + public DefaultExtActionFireRescue(AgentInfo agentInfo, WorldInfo worldInfo, ScenarioInfo scenarioInfo, ModuleManager moduleManager, DevelopData developData) { + super(agentInfo, worldInfo, scenarioInfo, moduleManager, developData); + this.target = null; + this.thresholdRest = developData + .getInteger("adf.impl.extaction.DefaultExtActionFireRescue.rest", 100); + + switch (scenarioInfo.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.pathPlanning = moduleManager.getModule( + "DefaultExtActionFireRescue.PathPlanning", + "adf_core_python.impl.module.algorithm.DijkstraPathPlanning"); + break; + } + } + + + public ExtAction precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + this.pathPlanning.precompute(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + public ExtAction resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.pathPlanning.resume(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + public ExtAction preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.pathPlanning.preparate(); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + public ExtAction updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + this.pathPlanning.updateInfo(messageManager); + return this; + } + + + @Override + public ExtAction setTarget(EntityID target) { + this.target = null; + if (target != null) { + StandardEntity entity = this.worldInfo.getEntity(target); + if (entity instanceof Human || entity instanceof Area) { + this.target = target; + return this; + } + } + return this; + } + + + @Override + public ExtAction calc() { + this.result = null; + FireBrigade agent = (FireBrigade) this.agentInfo.me(); + + if (this.needRest(agent)) { + EntityID areaID = this.convertArea(this.target); + ArrayList targets = new ArrayList<>(); + if (areaID != null) { + targets.add(areaID); + } + } + if (this.target != null) { + this.result = this.calcRescue(agent, this.pathPlanning, this.target); + } + return this; + } + + + private Action calcRescue(FireBrigade agent, PathPlanning pathPlanning, + EntityID targetID) { + StandardEntity targetEntity = this.worldInfo.getEntity(targetID); + if (targetEntity == null) { + return null; + } + EntityID agentPosition = agent.getPosition(); + if (targetEntity instanceof Human) { + Human human = (Human) targetEntity; + if (!human.isPositionDefined()) { + return null; + } + if (human.isHPDefined() && human.getHP() == 0) { + return null; + } + EntityID targetPosition = human.getPosition(); + if (agentPosition.getValue() == targetPosition.getValue()) { + if (human.isBuriednessDefined() && human.getBuriedness() > 0) { + return new ActionRescue(human); + } + } else { + List path = pathPlanning.getResult(agentPosition, + targetPosition); + if (path != null && path.size() > 0) { + return new ActionMove(path); + } + } + return null; + } + if (targetEntity.getStandardURN() == BLOCKADE) { + Blockade blockade = (Blockade) targetEntity; + if (blockade.isPositionDefined()) { + targetEntity = this.worldInfo.getEntity(blockade.getPosition()); + } + } + if (targetEntity instanceof Area) { + List path = pathPlanning.getResult(agentPosition, + targetEntity.getID()); + if (path != null && path.size() > 0) { + return new ActionMove(path); + } + } + return null; + } + + + private boolean needRest(Human agent) { + int hp = agent.getHP(); + int damage = agent.getDamage(); + if (hp == 0 || damage == 0) { + return false; + } + int activeTime = (hp / damage) + ((hp % damage) != 0 ? 1 : 0); + if (this.kernelTime == -1) { + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + } + return damage >= this.thresholdRest + || (activeTime + this.agentInfo.getTime()) < this.kernelTime; + } + + + private EntityID convertArea(EntityID targetID) { + StandardEntity entity = this.worldInfo.getEntity(targetID); + if (entity == null) { + return null; + } + if (entity instanceof Human) { + Human human = (Human) entity; + if (human.isPositionDefined()) { + EntityID position = human.getPosition(); + if (this.worldInfo.getEntity(position) instanceof Area) { + return position; + } + } + } else if (entity instanceof Area) { + return targetID; + } else if (entity.getStandardURN() == BLOCKADE) { + Blockade blockade = (Blockade) entity; + if (blockade.isPositionDefined()) { + return blockade.getPosition(); + } + } + return null; + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionMove.java b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionMove.java new file mode 100644 index 0000000..4f79cab --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionMove.java @@ -0,0 +1,210 @@ +package adf_core_python.impl.extaction; + +import adf.core.agent.action.Action; +import adf.core.agent.action.common.ActionMove; +import adf.core.agent.action.common.ActionRest; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.extaction.ExtAction; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import rescuecore2.config.NoSuchConfigOptionException; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class DefaultExtActionMove extends ExtAction { + + private PathPlanning pathPlanning; + + private int thresholdRest; + private int kernelTime; + + private EntityID target; + + public DefaultExtActionMove(AgentInfo agentInfo, WorldInfo worldInfo, ScenarioInfo scenarioInfo, ModuleManager moduleManager, DevelopData developData) { + super(agentInfo, worldInfo, scenarioInfo, moduleManager, developData); + this.target = null; + this.thresholdRest = developData + .getInteger("adf.impl.extaction.DefaultExtActionMove.rest", 100); + + switch (scenarioInfo.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.pathPlanning = moduleManager.getModule( + "DefaultExtActionMove.PathPlanning", + "adf_core_python.impl.module.algorithm.DijkstraPathPlanning"); + break; + } + } + + + @Override + public ExtAction precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + this.pathPlanning.precompute(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.pathPlanning.resume(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.pathPlanning.preparate(); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + @Override + public ExtAction updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + this.pathPlanning.updateInfo(messageManager); + return this; + } + + + @Override + public ExtAction setTarget(EntityID target) { + this.target = null; + StandardEntity entity = this.worldInfo.getEntity(target); + if (entity != null) { + if (entity.getStandardURN().equals(StandardEntityURN.BLOCKADE)) { + entity = this.worldInfo.getEntity(((Blockade) entity).getPosition()); + } else if (entity instanceof Human) { + entity = this.worldInfo.getPosition((Human) entity); + } + if (entity != null && entity instanceof Area) { + this.target = entity.getID(); + } + } + return this; + } + + + @Override + public ExtAction calc() { + this.result = null; + Human agent = (Human) this.agentInfo.me(); + + if (this.needRest(agent)) { + this.result = this.calcRest(agent, this.pathPlanning, this.target); + if (this.result != null) { + return this; + } + } + if (this.target == null) { + return this; + } + this.pathPlanning.setFrom(agent.getPosition()); + this.pathPlanning.setDestination(this.target); + List path = this.pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + this.result = new ActionMove(path); + } + return this; + } + + + private boolean needRest(Human agent) { + int hp = agent.getHP(); + int damage = agent.getDamage(); + if (hp == 0 || damage == 0) { + return false; + } + int activeTime = (hp / damage) + ((hp % damage) != 0 ? 1 : 0); + if (this.kernelTime == -1) { + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + } + return damage >= this.thresholdRest + || (activeTime + this.agentInfo.getTime()) < this.kernelTime; + } + + + private Action calcRest(Human human, PathPlanning pathPlanning, + EntityID target) { + EntityID position = human.getPosition(); + Collection refuges = this.worldInfo + .getEntityIDsOfType(StandardEntityURN.REFUGE); + int currentSize = refuges.size(); + if (refuges.contains(position)) { + return new ActionRest(); + } + List firstResult = null; + while (refuges.size() > 0) { + pathPlanning.setFrom(position); + pathPlanning.setDestination(refuges); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + if (firstResult == null) { + firstResult = new ArrayList<>(path); + if (target == null) { + break; + } + } + EntityID refugeID = path.get(path.size() - 1); + pathPlanning.setFrom(refugeID); + pathPlanning.setDestination(target); + List fromRefugeToTarget = pathPlanning.calc().getResult(); + if (fromRefugeToTarget != null && fromRefugeToTarget.size() > 0) { + return new ActionMove(path); + } + refuges.remove(refugeID); + // remove failed + if (currentSize == refuges.size()) { + break; + } + currentSize = refuges.size(); + } else { + break; + } + } + return firstResult != null ? new ActionMove(firstResult) : null; + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionTransport.java b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionTransport.java new file mode 100644 index 0000000..3d134e9 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/extaction/DefaultExtActionTransport.java @@ -0,0 +1,348 @@ +package adf_core_python.impl.extaction; + +import adf.core.agent.action.Action; +import adf.core.agent.action.ambulance.ActionLoad; +import adf.core.agent.action.ambulance.ActionUnload; +import adf.core.agent.action.common.ActionMove; +import adf.core.agent.action.common.ActionRest; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.extaction.ExtAction; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import com.google.common.collect.Lists; +import rescuecore2.config.NoSuchConfigOptionException; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static rescuecore2.standard.entities.StandardEntityURN.*; + +public class DefaultExtActionTransport extends ExtAction { + + private PathPlanning pathPlanning; + + private int thresholdRest; + private int kernelTime; + + private EntityID target; + + public DefaultExtActionTransport(AgentInfo agentInfo, WorldInfo worldInfo, ScenarioInfo scenarioInfo, ModuleManager moduleManager, DevelopData developData) { + super(agentInfo, worldInfo, scenarioInfo, moduleManager, developData); + this.target = null; + this.thresholdRest = developData + .getInteger("adf.impl.extaction.DefaultExtActionTransport.rest", 100); + + switch (scenarioInfo.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.pathPlanning = moduleManager.getModule( + "DefaultExtActionTransport.PathPlanning", + "adf_core_python.impl.module.algorithm.DijkstraPathPlanning"); + break; + } + } + + + public ExtAction precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + this.pathPlanning.precompute(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + public ExtAction resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.pathPlanning.resume(precomputeData); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + public ExtAction preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.pathPlanning.preparate(); + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + return this; + } + + + public ExtAction updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + this.pathPlanning.updateInfo(messageManager); + return this; + } + + + @Override + public ExtAction setTarget(EntityID target) { + this.target = null; + if (target != null) { + StandardEntity entity = this.worldInfo.getEntity(target); + if (entity instanceof Human || entity instanceof Area) { + this.target = target; + return this; + } + } + return this; + } + + + @Override + public ExtAction calc() { + this.result = null; + AmbulanceTeam agent = (AmbulanceTeam) this.agentInfo.me(); + Human transportHuman = this.agentInfo.someoneOnBoard(); + + if (transportHuman != null) { + this.result = this.calcUnload(agent, this.pathPlanning, transportHuman, + this.target); + if (this.result != null) { + return this; + } + } + if (this.needRest(agent)) { + EntityID areaID = this.convertArea(this.target); + ArrayList targets = new ArrayList<>(); + if (areaID != null) { + targets.add(areaID); + } + this.result = this.calcRefugeAction(agent, this.pathPlanning, targets, + false); + if (this.result != null) { + return this; + } + } + if (this.target != null) { + this.result = this.calcRescue(agent, this.pathPlanning, this.target); + } + return this; + } + + + private Action calcRescue(AmbulanceTeam agent, PathPlanning pathPlanning, + EntityID targetID) { + StandardEntity targetEntity = this.worldInfo.getEntity(targetID); + if (targetEntity == null) { + return null; + } + EntityID agentPosition = agent.getPosition(); + if (targetEntity instanceof Human) { + Human human = (Human) targetEntity; + if (!human.isPositionDefined()) { + return null; + } + if (human.isHPDefined() && human.getHP() == 0) { + return null; + } + EntityID targetPosition = human.getPosition(); + if (agentPosition.getValue() == targetPosition.getValue()) { + if ((human.getStandardURN() == CIVILIAN) && + (!human.isBuriednessDefined() || (human.isBuriednessDefined() && (human.getBuriedness() == 0)))) { + return new ActionLoad(human.getID()); + } + } else { + List path = pathPlanning.getResult(agentPosition, + targetPosition); + if (path != null && path.size() > 0) { + return new ActionMove(path); + } + } + return null; + } + if (targetEntity.getStandardURN() == BLOCKADE) { + Blockade blockade = (Blockade) targetEntity; + if (blockade.isPositionDefined()) { + targetEntity = this.worldInfo.getEntity(blockade.getPosition()); + } + } + if (targetEntity instanceof Area) { + List path = pathPlanning.getResult(agentPosition, + targetEntity.getID()); + if (path != null && path.size() > 0) { + return new ActionMove(path); + } + } + return null; + } + + + private Action calcUnload(AmbulanceTeam agent, PathPlanning pathPlanning, + Human transportHuman, EntityID targetID) { + if (transportHuman == null) { + return null; + } + if (transportHuman.isHPDefined() && transportHuman.getHP() == 0) { + return new ActionUnload(); + } + EntityID agentPosition = agent.getPosition(); + if (targetID == null + || transportHuman.getID().getValue() == targetID.getValue()) { + StandardEntity position = this.worldInfo.getEntity(agentPosition); + if (position != null && position.getStandardURN() == REFUGE) { + return new ActionUnload(); + } else { + pathPlanning.setFrom(agentPosition); + pathPlanning.setDestination(this.worldInfo.getEntityIDsOfType(REFUGE)); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + return new ActionMove(path); + } + } + } + if (targetID == null) { + return null; + } + StandardEntity targetEntity = this.worldInfo.getEntity(targetID); + if (targetEntity != null && targetEntity.getStandardURN() == BLOCKADE) { + Blockade blockade = (Blockade) targetEntity; + if (blockade.isPositionDefined()) { + targetEntity = this.worldInfo.getEntity(blockade.getPosition()); + } + } + if (targetEntity instanceof Area) { + if (agentPosition.getValue() == targetID.getValue()) { + return new ActionUnload(); + } else { + pathPlanning.setFrom(agentPosition); + pathPlanning.setDestination(targetID); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + return new ActionMove(path); + } + } + } else if (targetEntity instanceof Human) { + Human human = (Human) targetEntity; + if (human.isPositionDefined()) { + return calcRefugeAction(agent, pathPlanning, + Lists.newArrayList(human.getPosition()), true); + } + pathPlanning.setFrom(agentPosition); + pathPlanning.setDestination(this.worldInfo.getEntityIDsOfType(REFUGE)); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + return new ActionMove(path); + } + } + return null; + } + + + private boolean needRest(Human agent) { + int hp = agent.getHP(); + int damage = agent.getDamage(); + if (hp == 0 || damage == 0) { + return false; + } + int activeTime = (hp / damage) + ((hp % damage) != 0 ? 1 : 0); + if (this.kernelTime == -1) { + try { + this.kernelTime = this.scenarioInfo.getKernelTimesteps(); + } catch (NoSuchConfigOptionException e) { + this.kernelTime = -1; + } + } + return damage >= this.thresholdRest + || (activeTime + this.agentInfo.getTime()) < this.kernelTime; + } + + + private EntityID convertArea(EntityID targetID) { + StandardEntity entity = this.worldInfo.getEntity(targetID); + if (entity == null) { + return null; + } + if (entity instanceof Human) { + Human human = (Human) entity; + if (human.isPositionDefined()) { + EntityID position = human.getPosition(); + if (this.worldInfo.getEntity(position) instanceof Area) { + return position; + } + } + } else if (entity instanceof Area) { + return targetID; + } else if (entity.getStandardURN() == BLOCKADE) { + Blockade blockade = (Blockade) entity; + if (blockade.isPositionDefined()) { + return blockade.getPosition(); + } + } + return null; + } + + + private Action calcRefugeAction(Human human, PathPlanning pathPlanning, + Collection targets, boolean isUnload) { + EntityID position = human.getPosition(); + Collection refuges = this.worldInfo + .getEntityIDsOfType(StandardEntityURN.REFUGE); + int size = refuges.size(); + if (refuges.contains(position)) { + return isUnload ? new ActionUnload() : new ActionRest(); + } + List firstResult = null; + while (refuges.size() > 0) { + pathPlanning.setFrom(position); + pathPlanning.setDestination(refuges); + List path = pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + if (firstResult == null) { + firstResult = new ArrayList<>(path); + if (targets == null || targets.isEmpty()) { + break; + } + } + EntityID refugeID = path.get(path.size() - 1); + pathPlanning.setFrom(refugeID); + pathPlanning.setDestination(targets); + List fromRefugeToTarget = pathPlanning.calc().getResult(); + if (fromRefugeToTarget != null && fromRefugeToTarget.size() > 0) { + return new ActionMove(path); + } + refuges.remove(refugeID); + // remove failed + if (size == refuges.size()) { + break; + } + size = refuges.size(); + } else { + break; + } + } + return firstResult != null ? new ActionMove(firstResult) : null; + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/algorithm/AStarPathPlanning.java b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/AStarPathPlanning.java new file mode 100644 index 0000000..d8d8fba --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/AStarPathPlanning.java @@ -0,0 +1,198 @@ +package adf_core_python.impl.module.algorithm; + +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import rescuecore2.misc.collections.LazyMap; +import rescuecore2.standard.entities.Area; +import rescuecore2.worldmodel.Entity; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +public class AStarPathPlanning extends PathPlanning { + + private Map> graph; + + private EntityID from; + private Collection targets; + private List result; + + public AStarPathPlanning(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.init(); + } + + + private void init() { + Map> neighbours = new LazyMap>() { + + @Override + public Set createValue() { + return new HashSet<>(); + } + }; + for (Entity next : this.worldInfo) { + if (next instanceof Area) { + Collection areaNeighbours = ((Area) next).getNeighbours(); + neighbours.get(next.getID()).addAll(areaNeighbours); + } + } + this.graph = neighbours; + } + + + @Override + public List getResult() { + return this.result; + } + + + @Override + public PathPlanning setFrom(EntityID id) { + this.from = id; + return this; + } + + + @Override + public PathPlanning setDestination(Collection targets) { + this.targets = targets; + return this; + } + + + @Override + public PathPlanning precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + return this; + } + + + @Override + public PathPlanning resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + return this; + } + + + @Override + public PathPlanning preparate() { + super.preparate(); + return this; + } + + + @Override + public PathPlanning calc() { + // 1 + List open = new LinkedList<>(); + List close = new LinkedList<>(); + Map nodeMap = new HashMap<>(); + + // 3 + open.add(this.from); + nodeMap.put(this.from, new Node(null, this.from)); + close.clear(); + + while (true) { + // 4 + if (open.size() < 0) { + this.result = null; + return this; + } + + // 5 + Node n = null; + for (EntityID id : open) { + Node node = nodeMap.get(id); + + if (n == null) { + n = node; + } else if (node.estimate() < n.estimate()) { + n = node; + } + } + + // 6 + if (targets.contains(n.getID())) { + // 9 + List path = new LinkedList<>(); + while (n != null) { + path.add(0, n.getID()); + n = nodeMap.get(n.getParent()); + } + + this.result = path; + return this; + } + open.remove(n.getID()); + close.add(n.getID()); + + // 7 + Collection neighbours = this.graph.get(n.getID()); + for (EntityID neighbour : neighbours) { + Node m = new Node(n, neighbour); + + if (!open.contains(neighbour) && !close.contains(neighbour)) { + open.add(m.getID()); + nodeMap.put(neighbour, m); + } else if (open.contains(neighbour) + && m.estimate() < nodeMap.get(neighbour).estimate()) { + nodeMap.put(neighbour, m); + } else if (!close.contains(neighbour) + && m.estimate() < nodeMap.get(neighbour).estimate()) { + nodeMap.put(neighbour, m); + } + } + } + } + + private class Node { + + EntityID id; + EntityID parent; + + double cost; + double heuristic; + + public Node(Node from, EntityID id) { + this.id = id; + + if (from == null) { + this.cost = 0; + } else { + this.parent = from.getID(); + this.cost = from.getCost() + worldInfo.getDistance(from.getID(), id); + } + + this.heuristic = worldInfo.getDistance(id, + targets.toArray(new EntityID[targets.size()])[0]); + } + + + public EntityID getID() { + return id; + } + + + public double getCost() { + return cost; + } + + + public double estimate() { + return cost + heuristic; + } + + + public EntityID getParent() { + return this.parent; + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/algorithm/DijkstraPathPlanning.java b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/DijkstraPathPlanning.java new file mode 100644 index 0000000..c43aecd --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/DijkstraPathPlanning.java @@ -0,0 +1,154 @@ +package adf_core_python.impl.module.algorithm; + +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import rescuecore2.misc.collections.LazyMap; +import rescuecore2.standard.entities.Area; +import rescuecore2.worldmodel.Entity; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +public class DijkstraPathPlanning extends PathPlanning { + + private Map> graph; + + private EntityID from; + private Collection targets; + private List result; + + public DijkstraPathPlanning(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.init(); + } + + + private void init() { + Map> neighbours = new LazyMap>() { + + @Override + public Set createValue() { + return new HashSet<>(); + } + }; + for (Entity next : this.worldInfo) { + if (next instanceof Area) { + Collection areaNeighbours = ((Area) next).getNeighbours(); + neighbours.get(next.getID()).addAll(areaNeighbours); + } + } + this.graph = neighbours; + } + + + @Override + public List getResult() { + return this.result; + } + + + @Override + public PathPlanning setFrom(EntityID id) { + this.from = id; + return this; + } + + + @Override + public PathPlanning setDestination(Collection targets) { + this.targets = targets; + return this; + } + + + @Override + public PathPlanning updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + return this; + } + + + @Override + public PathPlanning precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + return this; + } + + + @Override + public PathPlanning resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + return this; + } + + + @Override + public PathPlanning preparate() { + super.preparate(); + return this; + } + + + @Override + public PathPlanning calc() { + List open = new LinkedList<>(); + Map ancestors = new HashMap<>(); + open.add(this.from); + EntityID next; + boolean found = false; + ancestors.put(this.from, this.from); + do { + next = open.remove(0); + if (isGoal(next, targets)) { + found = true; + break; + } + Collection neighbours = graph.get(next); + if (neighbours.isEmpty()) { + continue; + } + for (EntityID neighbour : neighbours) { + if (isGoal(neighbour, targets)) { + ancestors.put(neighbour, next); + next = neighbour; + found = true; + break; + } else { + if (!ancestors.containsKey(neighbour)) { + open.add(neighbour); + ancestors.put(neighbour, next); + } + } + } + } while (!found && !open.isEmpty()); + if (!found) { + // No path + this.result = null; + } + // Walk back from goal to this.from + EntityID current = next; + LinkedList path = new LinkedList<>(); + do { + path.add(0, current); + current = ancestors.get(current); + if (current == null) { + throw new RuntimeException( + "Found a node with no ancestor! Something is broken."); + } + } while (current != this.from); + this.result = path; + return this; + } + + + private boolean isGoal(EntityID e, Collection test) { + return test.contains(e); + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/algorithm/FireClustering.java b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/FireClustering.java new file mode 100644 index 0000000..b00053e --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/FireClustering.java @@ -0,0 +1,261 @@ +package adf_core_python.impl.module.algorithm; + +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.Clustering; +import adf_core_python.core.component.module.algorithm.DynamicClustering; +import rescuecore2.standard.entities.Building; +import rescuecore2.standard.entities.StandardEntity; +import rescuecore2.standard.entities.StandardEntityURN; +import rescuecore2.worldmodel.EntityID; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +public class FireClustering extends DynamicClustering { + + List> clusterList = new LinkedList<>(); + private int groupingDistance; + + public FireClustering(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.groupingDistance = developData.getInteger( + "adf.impl.module.algorithm.FireClustering.groupingDistance", 30); + } + + + /** + * calculation phase; update cluster + * + * @return own instance for method chaining + */ + @Override + public Clustering calc() { + for (EntityID changed : worldInfo.getChanged().getChangedEntities()) { + StandardEntity changedEntity = worldInfo.getEntity(changed); + if (changedEntity.getStandardURN().equals(StandardEntityURN.BUILDING)) { // changedEntity(cE) + // is + // a + // building + Building changedBuilding = (Building) changedEntity; + if (this.getClusterIndex(changedEntity) < 0) { // cE is not contained in + // cluster + if (isBurning(changedBuilding)) { // cE is burning building + ArrayList< + EntityID> hostClusterPropertyEntityIDs = new ArrayList<>(); + + // search host cluster + for (List cluster : this.clusterList) { + for (StandardEntity entity : cluster) { + if (worldInfo.getDistance(entity, + changedBuilding) <= groupingDistance) { + hostClusterPropertyEntityIDs.add(entity.getID()); + break; + } + } + } + + if (hostClusterPropertyEntityIDs.size() == 0) { // there is not host + // cluster : form + // new cluster + List cluster = new ArrayList<>(); + clusterList.add(cluster); + cluster.add(changedBuilding); + } else if (hostClusterPropertyEntityIDs.size() == 1) { // there is + // one host + // cluster : + // add + // building + // to the + // cluster + int hostIndex = this + .getClusterIndex(hostClusterPropertyEntityIDs.get(0)); + clusterList.get(hostIndex).add(changedBuilding); + } else { // there are multiple host clusters : add building to the + // cluster & combine clusters + int hostIndex = this + .getClusterIndex(hostClusterPropertyEntityIDs.get(0)); + List hostCluster = clusterList.get(hostIndex); + hostCluster.add(changedBuilding); + for (int index = 1; index < hostClusterPropertyEntityIDs + .size(); index++) { + int tergetClusterIndex = this + .getClusterIndex(hostClusterPropertyEntityIDs.get(index)); + hostCluster.addAll(clusterList.get(tergetClusterIndex)); + clusterList.remove(tergetClusterIndex); + } + } + } + } else { // cE is contained in cluster + if (!(isBurning(changedBuilding))) { // cE is not burning building + int hostClusterIndex = this.getClusterIndex(changedBuilding); + List< + StandardEntity> hostCluster = clusterList.get(hostClusterIndex); + + hostCluster.remove(changedBuilding); + + if (hostCluster.isEmpty()) { // host cluster is empty + clusterList.remove(hostClusterIndex); + } else { + // update cluster + List relatedBuilding = new ArrayList<>(); + relatedBuilding.addAll(hostCluster); + hostCluster.clear(); + + int clusterCount = 0; + while (!(relatedBuilding.isEmpty())) { + if ((clusterCount++) > 0) { + List cluster = new ArrayList<>(); + clusterList.add(cluster); + hostCluster = cluster; + } + + List openedBuilding = new LinkedList<>(); + openedBuilding.add(relatedBuilding.get(0)); + hostCluster.add(relatedBuilding.get(0)); + relatedBuilding.remove(0); + + while (!(openedBuilding.isEmpty())) { + for (StandardEntity entity : relatedBuilding) { + if (worldInfo.getDistance(openedBuilding.get(0), + entity) <= groupingDistance) { + openedBuilding.add(entity); + hostCluster.add(entity); + } + } + openedBuilding.remove(0); + relatedBuilding.removeAll(openedBuilding); + } + } + } + } + } + } + } + return this; + } + + + @Override + public Clustering updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() > 1) { + return this; + } + + this.calc(); // invoke calc() + + this.debugStdOut("Cluster : " + clusterList.size()); + + return this; + } + + + @Override + public Clustering precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() > 1) { + return this; + } + return this; + } + + + @Override + public Clustering resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() > 1) { + return this; + } + return this; + } + + + @Override + public Clustering preparate() { + super.preparate(); + if (this.getCountPreparate() > 1) { + return this; + } + return this; + } + + + @Override + public int getClusterNumber() { + return clusterList.size(); + } + + + @Override + public int getClusterIndex(StandardEntity standardEntity) { + for (int index = 0; index < clusterList.size(); index++) { + if (clusterList.get(index).contains(standardEntity)) { + return index; + } + } + return -1; + } + + + @Override + public int getClusterIndex(EntityID entityID) { + return getClusterIndex(worldInfo.getEntity(entityID)); + } + + + @Override + public Collection getClusterEntities(int i) { + return clusterList.get(i); + } + + + @Override + public Collection getClusterEntityIDs(int i) { + ArrayList list = new ArrayList<>(); + for (StandardEntity entity : getClusterEntities(i)) { + list.add(entity.getID()); + } + return list; + } + + + /** + * classify burning building + * + * @param building target building + * @return is building burning + */ + private boolean isBurning(Building building) { + if (building.isFierynessDefined()) { + switch (building.getFieryness()) { + case 1: + case 2: + case 3: + return true; + default: + return false; + } + } + return false; + } + + + /** + * output text with class name to STDOUT when debug-mode. + * + * @param text output text + */ + private void debugStdOut(String text) { + if (scenarioInfo.isDebugMode()) { + System.out.println("[" + this.getClass().getSimpleName() + "] " + text); + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/algorithm/KMeansClustering.java b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/KMeansClustering.java new file mode 100644 index 0000000..1dae975 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/algorithm/KMeansClustering.java @@ -0,0 +1,641 @@ +package adf_core_python.impl.module.algorithm; + +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.Clustering; +import adf_core_python.core.component.module.algorithm.StaticClustering; +import rescuecore2.misc.Pair; +import rescuecore2.misc.collections.LazyMap; +import rescuecore2.misc.geometry.Point2D; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.Entity; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +public class KMeansClustering extends StaticClustering { + + private static final String KEY_CLUSTER_SIZE = "clustering.size"; + private static final String KEY_CLUSTER_CENTER = "clustering.centers"; + private static final String KEY_CLUSTER_ENTITY = "clustering.entities."; + private static final String KEY_ASSIGN_AGENT = "clustering.assign"; + + private int repeatPrecompute; + private int repeatPreparate; + + private Collection entities; + + private List centerList; + private List centerIDs; + private Map> clusterEntitiesList; + private List> clusterEntityIDsList; + + private int clusterSize; + + private boolean assignAgentsFlag; + + private Map> shortestPathGraph; + + public KMeansClustering(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.repeatPrecompute = developData.getInteger( + "adf.impl.module.algorithm.KMeansClustering.repeatPrecompute", 7); + this.repeatPreparate = developData.getInteger( + "adf.impl.module.algorithm.KMeansClustering.repeatPreparate", 30); + this.clusterSize = developData.getInteger( + "adf.impl.module.algorithm.KMeansClustering.clusterSize", 5); + if (agentInfo.me().getStandardURN() + .equals(StandardEntityURN.AMBULANCE_TEAM)) { + this.clusterSize = scenarioInfo.getScenarioAgentsAt(); + } else if (agentInfo.me().getStandardURN() + .equals(StandardEntityURN.FIRE_BRIGADE)) { + this.clusterSize = scenarioInfo.getScenarioAgentsFb(); + } else if (agentInfo.me().getStandardURN() + .equals(StandardEntityURN.POLICE_FORCE)) { + this.clusterSize = scenarioInfo.getScenarioAgentsPf(); + } + this.assignAgentsFlag = developData.getBoolean( + "adf.impl.module.algorithm.KMeansClustering.assignAgentsFlag", true); + this.clusterEntityIDsList = new ArrayList<>(); + this.centerIDs = new ArrayList<>(); + this.clusterEntitiesList = new HashMap<>(); + this.centerList = new ArrayList<>(); + this.entities = wi.getEntitiesOfType(StandardEntityURN.ROAD, + StandardEntityURN.HYDRANT, StandardEntityURN.BUILDING, + StandardEntityURN.REFUGE, StandardEntityURN.GAS_STATION, + StandardEntityURN.AMBULANCE_CENTRE, StandardEntityURN.FIRE_STATION, + StandardEntityURN.POLICE_OFFICE); + } + + + @Override + public Clustering updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + this.centerList.clear(); + this.clusterEntitiesList.clear(); + return this; + } + + + @Override + public Clustering precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + this.calcPathBased(this.repeatPrecompute); + this.entities = null; + // write + precomputeData.setInteger(KEY_CLUSTER_SIZE, this.clusterSize); + precomputeData.setEntityIDList(KEY_CLUSTER_CENTER, this.centerIDs); + for (int i = 0; i < this.clusterSize; i++) { + precomputeData.setEntityIDList(KEY_CLUSTER_ENTITY + i, + this.clusterEntityIDsList.get(i)); + } + precomputeData.setBoolean(KEY_ASSIGN_AGENT, this.assignAgentsFlag); + return this; + } + + + @Override + public Clustering resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.entities = null; + // read + this.clusterSize = precomputeData.getInteger(KEY_CLUSTER_SIZE); + this.centerIDs = new ArrayList<>( + precomputeData.getEntityIDList(KEY_CLUSTER_CENTER)); + this.clusterEntityIDsList = new ArrayList<>(this.clusterSize); + for (int i = 0; i < this.clusterSize; i++) { + this.clusterEntityIDsList.add(i, + precomputeData.getEntityIDList(KEY_CLUSTER_ENTITY + i)); + } + this.assignAgentsFlag = precomputeData.getBoolean(KEY_ASSIGN_AGENT); + return this; + } + + + @Override + public Clustering preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.calcStandard(this.repeatPreparate); + this.entities = null; + return this; + } + + + @Override + public int getClusterNumber() { + // The number of clusters + return this.clusterSize; + } + + + @Override + public int getClusterIndex(StandardEntity entity) { + return this.getClusterIndex(entity.getID()); + } + + + @Override + public int getClusterIndex(EntityID id) { + for (int i = 0; i < this.clusterSize; i++) { + if (this.clusterEntityIDsList.get(i).contains(id)) { + return i; + } + } + return -1; + } + + + @Override + public Collection getClusterEntities(int index) { + List result = this.clusterEntitiesList.get(index); + if (result == null || result.isEmpty()) { + List list = this.clusterEntityIDsList.get(index); + result = new ArrayList<>(list.size()); + for (int i = 0; i < list.size(); i++) { + result.add(i, this.worldInfo.getEntity(list.get(i))); + } + this.clusterEntitiesList.put(index, result); + } + return result; + } + + + @Override + public Collection getClusterEntityIDs(int index) { + return this.clusterEntityIDsList.get(index); + } + + + @Override + public Clustering calc() { + return this; + } + + + private void calcStandard(int repeat) { + this.initShortestPath(this.worldInfo); + Random random = new Random(); + + List entityList = new ArrayList<>(this.entities); + this.centerList = new ArrayList<>(this.clusterSize); + this.clusterEntitiesList = new HashMap<>(this.clusterSize); + + // init list + for (int index = 0; index < this.clusterSize; index++) { + this.clusterEntitiesList.put(index, new ArrayList<>()); + this.centerList.add(index, entityList.get(0)); + } + System.out.println("[" + this.getClass().getSimpleName() + "] Cluster : " + + this.clusterSize); + // init center + for (int index = 0; index < this.clusterSize; index++) { + StandardEntity centerEntity; + do { + centerEntity = entityList + .get(Math.abs(random.nextInt()) % entityList.size()); + } while (this.centerList.contains(centerEntity)); + this.centerList.set(index, centerEntity); + } + // calc center + for (int i = 0; i < repeat; i++) { + this.clusterEntitiesList.clear(); + for (int index = 0; index < this.clusterSize; index++) { + this.clusterEntitiesList.put(index, new ArrayList<>()); + } + for (StandardEntity entity : entityList) { + StandardEntity tmp = this.getNearEntityByLine(this.worldInfo, + this.centerList, entity); + this.clusterEntitiesList.get(this.centerList.indexOf(tmp)).add(entity); + } + for (int index = 0; index < this.clusterSize; index++) { + int sumX = 0, sumY = 0; + for (StandardEntity entity : this.clusterEntitiesList.get(index)) { + Pair location = this.worldInfo.getLocation(entity); + sumX += location.first(); + sumY += location.second(); + } + int centerX = sumX / this.clusterEntitiesList.get(index).size(); + int centerY = sumY / this.clusterEntitiesList.get(index).size(); + StandardEntity center = this.getNearEntityByLine(this.worldInfo, + this.clusterEntitiesList.get(index), centerX, centerY); + if (center instanceof Area) { + this.centerList.set(index, center); + } else if (center instanceof Human) { + this.centerList.set(index, + this.worldInfo.getEntity(((Human) center).getPosition())); + } else if (center instanceof Blockade) { + this.centerList.set(index, + this.worldInfo.getEntity(((Blockade) center).getPosition())); + } + } + if (scenarioInfo.isDebugMode()) { + System.out.print("*"); + } + } + + if (scenarioInfo.isDebugMode()) { + System.out.println(); + } + + // set entity + this.clusterEntitiesList.clear(); + for (int index = 0; index < this.clusterSize; index++) { + this.clusterEntitiesList.put(index, new ArrayList<>()); + } + for (StandardEntity entity : entityList) { + StandardEntity tmp = this.getNearEntityByLine(this.worldInfo, + this.centerList, entity); + this.clusterEntitiesList.get(this.centerList.indexOf(tmp)).add(entity); + } + + // this.clusterEntitiesList.sort(comparing(List::size, reverseOrder())); + + if (this.assignAgentsFlag) { + List firebrigadeList = new ArrayList<>( + this.worldInfo.getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE)); + List policeforceList = new ArrayList<>( + this.worldInfo.getEntitiesOfType(StandardEntityURN.POLICE_FORCE)); + List ambulanceteamList = new ArrayList<>( + this.worldInfo.getEntitiesOfType(StandardEntityURN.AMBULANCE_TEAM)); + + this.assignAgents(this.worldInfo, firebrigadeList); + this.assignAgents(this.worldInfo, policeforceList); + this.assignAgents(this.worldInfo, ambulanceteamList); + } + + this.centerIDs = new ArrayList<>(); + for (int i = 0; i < this.centerList.size(); i++) { + this.centerIDs.add(i, this.centerList.get(i).getID()); + } + for (int index = 0; index < this.clusterSize; index++) { + List entities = this.clusterEntitiesList.get(index); + List list = new ArrayList<>(entities.size()); + for (int i = 0; i < entities.size(); i++) { + list.add(i, entities.get(i).getID()); + } + this.clusterEntityIDsList.add(index, list); + } + } + + + private void calcPathBased(int repeat) { + this.initShortestPath(this.worldInfo); + Random random = new Random(); + List entityList = new ArrayList<>(this.entities); + this.centerList = new ArrayList<>(this.clusterSize); + this.clusterEntitiesList = new HashMap<>(this.clusterSize); + + for (int index = 0; index < this.clusterSize; index++) { + this.clusterEntitiesList.put(index, new ArrayList<>()); + this.centerList.add(index, entityList.get(0)); + } + for (int index = 0; index < this.clusterSize; index++) { + StandardEntity centerEntity; + do { + centerEntity = entityList + .get(Math.abs(random.nextInt()) % entityList.size()); + } while (this.centerList.contains(centerEntity)); + this.centerList.set(index, centerEntity); + } + for (int i = 0; i < repeat; i++) { + this.clusterEntitiesList.clear(); + for (int index = 0; index < this.clusterSize; index++) { + this.clusterEntitiesList.put(index, new ArrayList<>()); + } + for (StandardEntity entity : entityList) { + StandardEntity tmp = this.getNearEntity(this.worldInfo, this.centerList, + entity); + this.clusterEntitiesList.get(this.centerList.indexOf(tmp)).add(entity); + } + for (int index = 0; index < this.clusterSize; index++) { + int sumX = 0, sumY = 0; + for (StandardEntity entity : this.clusterEntitiesList.get(index)) { + Pair location = this.worldInfo.getLocation(entity); + sumX += location.first(); + sumY += location.second(); + } + int centerX = sumX / clusterEntitiesList.get(index).size(); + int centerY = sumY / clusterEntitiesList.get(index).size(); + + // this.centerList.set(index, getNearEntity(this.worldInfo, + // this.clusterEntitiesList.get(index), centerX, centerY)); + StandardEntity center = this.getNearEntity(this.worldInfo, + this.clusterEntitiesList.get(index), centerX, centerY); + if (center instanceof Area) { + this.centerList.set(index, center); + } else if (center instanceof Human) { + this.centerList.set(index, + this.worldInfo.getEntity(((Human) center).getPosition())); + } else if (center instanceof Blockade) { + this.centerList.set(index, + this.worldInfo.getEntity(((Blockade) center).getPosition())); + } + } + if (scenarioInfo.isDebugMode()) { + System.out.print("*"); + } + } + + if (scenarioInfo.isDebugMode()) { + System.out.println(); + } + + this.clusterEntitiesList.clear(); + for (int index = 0; index < this.clusterSize; index++) { + this.clusterEntitiesList.put(index, new ArrayList<>()); + } + for (StandardEntity entity : entityList) { + StandardEntity tmp = this.getNearEntity(this.worldInfo, this.centerList, + entity); + this.clusterEntitiesList.get(this.centerList.indexOf(tmp)).add(entity); + } + // this.clusterEntitiesList.sort(comparing(List::size, reverseOrder())); + if (this.assignAgentsFlag) { + List fireBrigadeList = new ArrayList<>( + this.worldInfo.getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE)); + List policeForceList = new ArrayList<>( + this.worldInfo.getEntitiesOfType(StandardEntityURN.POLICE_FORCE)); + List ambulanceTeamList = new ArrayList<>( + this.worldInfo.getEntitiesOfType(StandardEntityURN.AMBULANCE_TEAM)); + this.assignAgents(this.worldInfo, fireBrigadeList); + this.assignAgents(this.worldInfo, policeForceList); + this.assignAgents(this.worldInfo, ambulanceTeamList); + } + + this.centerIDs = new ArrayList<>(); + for (int i = 0; i < this.centerList.size(); i++) { + this.centerIDs.add(i, this.centerList.get(i).getID()); + } + for (int index = 0; index < this.clusterSize; index++) { + List entities = this.clusterEntitiesList.get(index); + List list = new ArrayList<>(entities.size()); + for (int i = 0; i < entities.size(); i++) { + list.add(i, entities.get(i).getID()); + } + this.clusterEntityIDsList.add(index, list); + } + } + + + private void assignAgents(WorldInfo world, List agentList) { + int clusterIndex = 0; + while (agentList.size() > 0) { + StandardEntity center = this.centerList.get(clusterIndex); + StandardEntity agent = this.getNearAgent(world, agentList, center); + this.clusterEntitiesList.get(clusterIndex).add(agent); + agentList.remove(agent); + clusterIndex++; + if (clusterIndex >= this.clusterSize) { + clusterIndex = 0; + } + } + } + + + private StandardEntity getNearEntityByLine(WorldInfo world, + List srcEntityList, StandardEntity targetEntity) { + Pair location = world.getLocation(targetEntity); + return this.getNearEntityByLine(world, srcEntityList, location.first(), + location.second()); + } + + + private StandardEntity getNearEntityByLine(WorldInfo world, + List srcEntityList, int targetX, int targetY) { + StandardEntity result = null; + for (StandardEntity entity : srcEntityList) { + result = ((result != null) + ? this.compareLineDistance(world, targetX, targetY, result, entity) + : entity); + } + return result; + } + + + private StandardEntity getNearAgent(WorldInfo worldInfo, + List srcAgentList, StandardEntity targetEntity) { + StandardEntity result = null; + for (StandardEntity agent : srcAgentList) { + Human human = (Human) agent; + if (result == null) { + result = agent; + } else { + if (this + .comparePathDistance(worldInfo, targetEntity, result, + worldInfo.getPosition(human)) + .equals(worldInfo.getPosition(human))) { + result = agent; + } + } + } + return result; + } + + + private StandardEntity getNearEntity(WorldInfo worldInfo, + List srcEntityList, int targetX, int targetY) { + StandardEntity result = null; + for (StandardEntity entity : srcEntityList) { + result = (result != null) + ? this.compareLineDistance(worldInfo, targetX, targetY, result, + entity) + : entity; + } + return result; + } + + + private Point2D getEdgePoint(Edge edge) { + Point2D start = edge.getStart(); + Point2D end = edge.getEnd(); + return new Point2D(((start.getX() + end.getX()) / 2.0D), + ((start.getY() + end.getY()) / 2.0D)); + } + + + private double getDistance(double fromX, double fromY, double toX, + double toY) { + double dx = fromX - toX; + double dy = fromY - toY; + return Math.hypot(dx, dy); + } + + + private double getDistance(Pair from, Point2D to) { + return getDistance(from.first(), from.second(), to.getX(), to.getY()); + } + + + private double getDistance(Pair from, Edge to) { + return getDistance(from, getEdgePoint(to)); + } + + + private double getDistance(Point2D from, Point2D to) { + return getDistance(from.getX(), from.getY(), to.getX(), to.getY()); + } + + + private double getDistance(Edge from, Edge to) { + return getDistance(getEdgePoint(from), getEdgePoint(to)); + } + + + private StandardEntity compareLineDistance(WorldInfo worldInfo, int targetX, + int targetY, StandardEntity first, StandardEntity second) { + Pair firstLocation = worldInfo.getLocation(first); + Pair secondLocation = worldInfo.getLocation(second); + double firstDistance = getDistance(firstLocation.first(), + firstLocation.second(), targetX, targetY); + double secondDistance = getDistance(secondLocation.first(), + secondLocation.second(), targetX, targetY); + return (firstDistance < secondDistance ? first : second); + } + + + private StandardEntity getNearEntity(WorldInfo worldInfo, + List srcEntityList, StandardEntity targetEntity) { + StandardEntity result = null; + for (StandardEntity entity : srcEntityList) { + result = (result != null) + ? this.comparePathDistance(worldInfo, targetEntity, result, entity) + : entity; + } + return result; + } + + + private StandardEntity comparePathDistance(WorldInfo worldInfo, + StandardEntity target, StandardEntity first, StandardEntity second) { + double firstDistance = getPathDistance(worldInfo, + shortestPath(target.getID(), first.getID())); + double secondDistance = getPathDistance(worldInfo, + shortestPath(target.getID(), second.getID())); + return (firstDistance < secondDistance ? first : second); + } + + + private double getPathDistance(WorldInfo worldInfo, List path) { + if (path == null) + return Double.MAX_VALUE; + if (path.size() <= 1) + return 0.0D; + + double distance = 0.0D; + int limit = path.size() - 1; + + Area area = (Area) worldInfo.getEntity(path.get(0)); + distance += getDistance(worldInfo.getLocation(area), + area.getEdgeTo(path.get(1))); + area = (Area) worldInfo.getEntity(path.get(limit)); + distance += getDistance(worldInfo.getLocation(area), + area.getEdgeTo(path.get(limit - 1))); + + for (int i = 1; i < limit; i++) { + area = (Area) worldInfo.getEntity(path.get(i)); + distance += getDistance(area.getEdgeTo(path.get(i - 1)), + area.getEdgeTo(path.get(i + 1))); + } + return distance; + } + + + private void initShortestPath(WorldInfo worldInfo) { + Map> neighbours = new LazyMap>() { + + @Override + public Set createValue() { + return new HashSet<>(); + } + }; + for (Entity next : worldInfo) { + if (next instanceof Area) { + Collection areaNeighbours = ((Area) next).getNeighbours(); + neighbours.get(next.getID()).addAll(areaNeighbours); + } + } + for (Map.Entry> graph : neighbours.entrySet()) {// fix + // graph + for (EntityID entityID : graph.getValue()) { + neighbours.get(entityID).add(graph.getKey()); + } + } + this.shortestPathGraph = neighbours; + } + + + private List shortestPath(EntityID start, EntityID... goals) { + return shortestPath(start, Arrays.asList(goals)); + } + + + private List shortestPath(EntityID start, + Collection goals) { + List open = new LinkedList<>(); + Map ancestors = new HashMap<>(); + open.add(start); + EntityID next; + boolean found = false; + ancestors.put(start, start); + do { + next = open.remove(0); + if (isGoal(next, goals)) { + found = true; + break; + } + Collection neighbours = shortestPathGraph.get(next); + if (neighbours.isEmpty()) + continue; + + for (EntityID neighbour : neighbours) { + if (isGoal(neighbour, goals)) { + ancestors.put(neighbour, next); + next = neighbour; + found = true; + break; + } else if (!ancestors.containsKey(neighbour)) { + open.add(neighbour); + ancestors.put(neighbour, next); + } + } + } while (!found && !open.isEmpty()); + if (!found) { + // No path + return null; + } + // Walk back from goal to start + EntityID current = next; + List path = new LinkedList<>(); + do { + path.add(0, current); + current = ancestors.get(current); + if (current == null) + throw new RuntimeException( + "Found a node with no ancestor! Something is broken."); + } while (current != start); + return path; + } + + + private boolean isGoal(EntityID e, Collection test) { + return test.contains(e); + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/comm/DefaultChannelSubscriber.java b/java/lib/src/main/java/adf_core_python/impl/module/comm/DefaultChannelSubscriber.java new file mode 100644 index 0000000..b84ff49 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/comm/DefaultChannelSubscriber.java @@ -0,0 +1,96 @@ +package adf_core_python.impl.module.comm; + +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.component.communication.ChannelSubscriber; +import rescuecore2.standard.entities.StandardEntityURN; + +public class DefaultChannelSubscriber extends ChannelSubscriber { + + public static int getChannelNumber(StandardEntityURN agentType, + int channelIndex, int numChannels) { + int agentIndex = 0; + if (agentType == StandardEntityURN.FIRE_BRIGADE + || agentType == StandardEntityURN.FIRE_STATION) { + agentIndex = 1; + } else if (agentType == StandardEntityURN.POLICE_FORCE + || agentType == StandardEntityURN.POLICE_OFFICE) { + agentIndex = 2; + } else if (agentType == StandardEntityURN.AMBULANCE_TEAM + || agentType == StandardEntityURN.AMBULANCE_CENTRE) { + agentIndex = 3; + } + + int index = (3 * channelIndex) + agentIndex; + if ((index % numChannels) == 0) { + index = numChannels; + } else { + index = index % numChannels; + } + return index; + } + + public static void main(String[] args) { + int numChannels = 6; + int maxChannels = 2; + for (int i = 0; i < maxChannels; i++) { + System.out.println("FIREBRIGADE-" + i + ":" + + getChannelNumber(StandardEntityURN.FIRE_BRIGADE, i, numChannels)); + } + for (int i = 0; i < maxChannels; i++) { + System.out.println("POLICE-" + i + ":" + + getChannelNumber(StandardEntityURN.POLICE_OFFICE, i, numChannels)); + } + for (int i = 0; i < maxChannels; i++) { + System.out.println("AMB-" + i + ":" + getChannelNumber( + StandardEntityURN.AMBULANCE_CENTRE, i, numChannels)); + } + } + + @Override + public void subscribe(AgentInfo agentInfo, WorldInfo worldInfo, + ScenarioInfo scenarioInfo, MessageManager messageManager) { + // subscribe only once at the beginning + if (agentInfo.getTime() == 1) { + int numChannels = scenarioInfo.getCommsChannelsCount() - 1; // 0th channel + // is the + // voice + // channel + + int maxChannelCount = 0; + boolean isPlatoon = isPlatoonAgent(agentInfo, worldInfo); + if (isPlatoon) { + maxChannelCount = scenarioInfo.getCommsChannelsMaxPlatoon(); + } else { + maxChannelCount = scenarioInfo.getCommsChannelsMaxOffice(); + } + + StandardEntityURN agentType = getAgentType(agentInfo, worldInfo); + int[] channels = new int[maxChannelCount]; + for (int i = 0; i < maxChannelCount; i++) { + channels[i] = getChannelNumber(agentType, i, numChannels); + } + + messageManager.subscribeToChannels(channels); + } + } + + protected boolean isPlatoonAgent(AgentInfo agentInfo, WorldInfo worldInfo) { + StandardEntityURN agentType = getAgentType(agentInfo, worldInfo); + if (agentType == StandardEntityURN.FIRE_BRIGADE + || agentType == StandardEntityURN.POLICE_FORCE + || agentType == StandardEntityURN.AMBULANCE_TEAM) { + return true; + } + return false; + } + + protected StandardEntityURN getAgentType(AgentInfo agentInfo, + WorldInfo worldInfo) { + StandardEntityURN agentType = worldInfo.getEntity(agentInfo.getID()) + .getStandardURN(); + return agentType; + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/comm/DefaultMessageCoordinator.java b/java/lib/src/main/java/adf_core_python/impl/module/comm/DefaultMessageCoordinator.java new file mode 100644 index 0000000..07ee3f2 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/comm/DefaultMessageCoordinator.java @@ -0,0 +1,199 @@ +package adf_core_python.impl.module.comm; + +import adf.core.agent.communication.standard.bundle.StandardMessage; +import adf.core.agent.communication.standard.bundle.StandardMessagePriority; +import adf.core.agent.communication.standard.bundle.centralized.*; +import adf.core.agent.communication.standard.bundle.information.*; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf.core.component.communication.CommunicationMessage; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.component.communication.MessageCoordinator; +import rescuecore2.standard.entities.StandardEntityURN; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultMessageCoordinator extends MessageCoordinator { + + @Override + public void coordinate(AgentInfo agentInfo, WorldInfo worldInfo, + ScenarioInfo scenarioInfo, MessageManager messageManager, + ArrayList sendMessageList, + List> channelSendMessageList) { + + // have different lists for every agent + ArrayList policeMessages = new ArrayList<>(); + ArrayList ambulanceMessages = new ArrayList<>(); + ArrayList fireBrigadeMessages = new ArrayList<>(); + + ArrayList voiceMessages = new ArrayList<>(); + + StandardEntityURN agentType = getAgentType(agentInfo, worldInfo); + + for (CommunicationMessage msg : sendMessageList) { + if (msg instanceof StandardMessage + && !((StandardMessage) msg).isRadio()) { + voiceMessages.add(msg); + } else { + if (msg instanceof MessageBuilding) { + fireBrigadeMessages.add(msg); + } else if (msg instanceof MessageCivilian) { + ambulanceMessages.add(msg); + } else if (msg instanceof MessageRoad) { + fireBrigadeMessages.add(msg); + ambulanceMessages.add(msg); + policeMessages.add(msg); + } else if (msg instanceof CommandAmbulance) { + ambulanceMessages.add(msg); + } else if (msg instanceof CommandFire) { + fireBrigadeMessages.add(msg); + } else if (msg instanceof CommandPolice) { + policeMessages.add(msg); + } else if (msg instanceof CommandScout) { + if (agentType == StandardEntityURN.FIRE_STATION) { + fireBrigadeMessages.add(msg); + } else if (agentType == StandardEntityURN.POLICE_OFFICE) { + policeMessages.add(msg); + } else if (agentType == StandardEntityURN.AMBULANCE_CENTRE) { + ambulanceMessages.add(msg); + } + } else if (msg instanceof MessageReport) { + if (agentType == StandardEntityURN.FIRE_BRIGADE) { + fireBrigadeMessages.add(msg); + } else if (agentType == StandardEntityURN.POLICE_FORCE) { + policeMessages.add(msg); + } else if (agentType == StandardEntityURN.AMBULANCE_TEAM) { + ambulanceMessages.add(msg); + } + } else if (msg instanceof MessageFireBrigade) { + fireBrigadeMessages.add(msg); + ambulanceMessages.add(msg); + policeMessages.add(msg); + } else if (msg instanceof MessagePoliceForce) { + ambulanceMessages.add(msg); + policeMessages.add(msg); + } else if (msg instanceof MessageAmbulanceTeam) { + ambulanceMessages.add(msg); + policeMessages.add(msg); + } + } + } + + if (scenarioInfo.getCommsChannelsCount() > 1) { + // send radio messages if there are more than one communication channel + int[] channelSize = new int[scenarioInfo.getCommsChannelsCount() - 1]; + + setSendMessages(scenarioInfo, StandardEntityURN.POLICE_FORCE, agentInfo, + worldInfo, policeMessages, channelSendMessageList, channelSize); + setSendMessages(scenarioInfo, StandardEntityURN.AMBULANCE_TEAM, agentInfo, + worldInfo, ambulanceMessages, channelSendMessageList, channelSize); + setSendMessages(scenarioInfo, StandardEntityURN.FIRE_BRIGADE, agentInfo, + worldInfo, fireBrigadeMessages, channelSendMessageList, channelSize); + } + + ArrayList voiceMessageLowList = new ArrayList<>(); + ArrayList voiceMessageNormalList = new ArrayList<>(); + ArrayList voiceMessageHighList = new ArrayList<>(); + + for (CommunicationMessage msg : voiceMessages) { + if (msg instanceof StandardMessage) { + StandardMessage m = (StandardMessage) msg; + switch (m.getSendingPriority()) { + case LOW: + voiceMessageLowList.add(m); + break; + case NORMAL: + voiceMessageNormalList.add(m); + break; + case HIGH: + voiceMessageHighList.add(m); + break; + } + } + } + + // set the voice channel messages + channelSendMessageList.get(0).addAll(voiceMessageHighList); + channelSendMessageList.get(0).addAll(voiceMessageNormalList); + channelSendMessageList.get(0).addAll(voiceMessageLowList); + } + + + protected int[] getChannelsByAgentType(StandardEntityURN agentType, + AgentInfo agentInfo, WorldInfo worldInfo, ScenarioInfo scenarioInfo, + int channelIndex) { + int numChannels = scenarioInfo.getCommsChannelsCount() - 1; // 0th channel + // is the voice + // channel + int maxChannelCount = 0; + boolean isPlatoon = isPlatoonAgent(agentInfo, worldInfo); + if (isPlatoon) { + maxChannelCount = scenarioInfo.getCommsChannelsMaxPlatoon(); + } else { + maxChannelCount = scenarioInfo.getCommsChannelsMaxOffice(); + } + int[] channels = new int[maxChannelCount]; + + for (int i = 0; i < maxChannelCount; i++) { + channels[i] = DefaultChannelSubscriber.getChannelNumber(agentType, i, + numChannels); + } + return channels; + } + + + protected boolean isPlatoonAgent(AgentInfo agentInfo, WorldInfo worldInfo) { + StandardEntityURN agentType = getAgentType(agentInfo, worldInfo); + if (agentType == StandardEntityURN.FIRE_BRIGADE + || agentType == StandardEntityURN.POLICE_FORCE + || agentType == StandardEntityURN.AMBULANCE_TEAM) { + return true; + } + return false; + } + + + protected StandardEntityURN getAgentType(AgentInfo agentInfo, + WorldInfo worldInfo) { + StandardEntityURN agentType = worldInfo.getEntity(agentInfo.getID()) + .getStandardURN(); + return agentType; + } + + + protected void setSendMessages(ScenarioInfo scenarioInfo, + StandardEntityURN agentType, AgentInfo agentInfo, WorldInfo worldInfo, + List messages, + List> channelSendMessageList, + int[] channelSize) { + int channelIndex = 0; + int[] channels = getChannelsByAgentType(agentType, agentInfo, worldInfo, + scenarioInfo, channelIndex); + int channel = channels[channelIndex]; + int channelCapacity = scenarioInfo.getCommsChannelBandwidth(channel); + // start from HIGH, NORMAL, to LOW + for (int i = StandardMessagePriority.values().length - 1; i >= 0; i--) { + for (CommunicationMessage msg : messages) { + StandardMessage smsg = (StandardMessage) msg; + if (smsg.getSendingPriority() == StandardMessagePriority.values()[i]) { + channelSize[channel - 1] += smsg.getByteArraySize(); + if (channelSize[channel - 1] > channelCapacity) { + channelSize[channel - 1] -= smsg.getByteArraySize(); + channelIndex++; + if (channelIndex < channels.length) { + channel = channels[channelIndex]; + channelCapacity = scenarioInfo.getCommsChannelBandwidth(channel); + channelSize[channel - 1] += smsg.getByteArraySize(); + } else { + // if there is no new channel for that message types, just break + break; + } + } + channelSendMessageList.get(channel).add(smsg); + } + } + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultAmbulanceTargetAllocator.java b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultAmbulanceTargetAllocator.java new file mode 100644 index 0000000..75d2b0e --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultAmbulanceTargetAllocator.java @@ -0,0 +1,362 @@ +package adf_core_python.impl.module.complex; + +import adf.core.agent.communication.standard.bundle.MessageUtil; +import adf.core.agent.communication.standard.bundle.centralized.CommandAmbulance; +import adf.core.agent.communication.standard.bundle.centralized.MessageReport; +import adf.core.agent.communication.standard.bundle.information.MessageAmbulanceTeam; +import adf.core.agent.communication.standard.bundle.information.MessageCivilian; +import adf.core.agent.communication.standard.bundle.information.MessageFireBrigade; +import adf.core.agent.communication.standard.bundle.information.MessagePoliceForce; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf.core.component.communication.CommunicationMessage; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.AmbulanceTargetAllocator; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +import static rescuecore2.standard.entities.StandardEntityURN.REFUGE; + +public class DefaultAmbulanceTargetAllocator extends AmbulanceTargetAllocator { + + private Collection priorityHumans; + private Collection targetHumans; + + private Map ambulanceTeamInfoMap; + + public DefaultAmbulanceTargetAllocator(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.priorityHumans = new HashSet<>(); + this.targetHumans = new HashSet<>(); + this.ambulanceTeamInfoMap = new HashMap<>(); + } + + + @Override + public AmbulanceTargetAllocator resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + for (EntityID id : this.worldInfo + .getEntityIDsOfType(StandardEntityURN.AMBULANCE_TEAM)) { + this.ambulanceTeamInfoMap.put(id, new AmbulanceTeamInfo(id)); + } + return this; + } + + + @Override + public AmbulanceTargetAllocator preparate() { + super.preparate(); + if (this.getCountPrecompute() >= 2) { + return this; + } + for (EntityID id : this.worldInfo + .getEntityIDsOfType(StandardEntityURN.AMBULANCE_TEAM)) { + this.ambulanceTeamInfoMap.put(id, new AmbulanceTeamInfo(id)); + } + return this; + } + + + @Override + public Map getResult() { + return this.convert(this.ambulanceTeamInfoMap); + } + + + @Override + public AmbulanceTargetAllocator calc() { + List agents = this + .getActionAgents(this.ambulanceTeamInfoMap); + Collection removes = new ArrayList<>(); + int currentTime = this.agentInfo.getTime(); + for (EntityID target : this.priorityHumans) { + if (agents.size() > 0) { + StandardEntity targetEntity = this.worldInfo.getEntity(target); + if (targetEntity != null && targetEntity instanceof Human + && ((Human) targetEntity).isPositionDefined()) { + agents.sort(new DistanceSorter(this.worldInfo, targetEntity)); + StandardEntity result = agents.get(0); + agents.remove(0); + AmbulanceTeamInfo info = this.ambulanceTeamInfoMap + .get(result.getID()); + if (info != null) { + info.canNewAction = false; + info.target = target; + info.commandTime = currentTime; + this.ambulanceTeamInfoMap.put(result.getID(), info); + removes.add(target); + } + } + } + } + this.priorityHumans.removeAll(removes); + removes.clear(); + for (EntityID target : this.targetHumans) { + if (agents.size() > 0) { + StandardEntity targetEntity = this.worldInfo.getEntity(target); + if (targetEntity != null && targetEntity instanceof Human + && ((Human) targetEntity).isPositionDefined()) { + agents.sort(new DistanceSorter(this.worldInfo, targetEntity)); + StandardEntity result = agents.get(0); + agents.remove(0); + AmbulanceTeamInfo info = this.ambulanceTeamInfoMap + .get(result.getID()); + if (info != null) { + info.canNewAction = false; + info.target = target; + info.commandTime = currentTime; + this.ambulanceTeamInfoMap.put(result.getID(), info); + removes.add(target); + } + } + } + } + this.targetHumans.removeAll(removes); + return this; + } + + + @Override + public AmbulanceTargetAllocator updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + int currentTime = this.agentInfo.getTime(); + for (CommunicationMessage message : messageManager + .getReceivedMessageList()) { + Class messageClass = message.getClass(); + if (messageClass == MessageCivilian.class) { + MessageCivilian mc = (MessageCivilian) message; + MessageUtil.reflectMessage(this.worldInfo, mc); + if (mc.isBuriednessDefined() && mc.getBuriedness() > 0) { + this.targetHumans.add(mc.getAgentID()); + } else { + this.priorityHumans.remove(mc.getAgentID()); + this.targetHumans.remove(mc.getAgentID()); + } + } else if (messageClass == MessageFireBrigade.class) { + MessageFireBrigade mfb = (MessageFireBrigade) message; + MessageUtil.reflectMessage(this.worldInfo, mfb); + if (mfb.isBuriednessDefined() && mfb.getBuriedness() > 0) { + this.priorityHumans.add(mfb.getAgentID()); + } else { + this.priorityHumans.remove(mfb.getAgentID()); + this.targetHumans.remove(mfb.getAgentID()); + } + } else if (messageClass == MessagePoliceForce.class) { + MessagePoliceForce mpf = (MessagePoliceForce) message; + MessageUtil.reflectMessage(this.worldInfo, mpf); + if (mpf.isBuriednessDefined() && mpf.getBuriedness() > 0) { + this.priorityHumans.add(mpf.getAgentID()); + } else { + this.priorityHumans.remove(mpf.getAgentID()); + this.targetHumans.remove(mpf.getAgentID()); + } + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(MessageAmbulanceTeam.class)) { + MessageAmbulanceTeam mat = (MessageAmbulanceTeam) message; + MessageUtil.reflectMessage(this.worldInfo, mat); + if (mat.isBuriednessDefined() && mat.getBuriedness() > 0) { + this.priorityHumans.add(mat.getAgentID()); + } else { + this.priorityHumans.remove(mat.getAgentID()); + this.targetHumans.remove(mat.getAgentID()); + } + AmbulanceTeamInfo info = this.ambulanceTeamInfoMap.get(mat.getAgentID()); + if (info == null) { + info = new AmbulanceTeamInfo(mat.getAgentID()); + } + if (currentTime >= info.commandTime + 2) { + this.ambulanceTeamInfoMap.put(mat.getAgentID(), this.update(info, mat)); + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(CommandAmbulance.class)) { + CommandAmbulance command = (CommandAmbulance) message; + if (command.getAction() == CommandAmbulance.ACTION_RESCUE + && command.isBroadcast()) { + this.priorityHumans.add(command.getTargetID()); + this.targetHumans.add(command.getTargetID()); + } else if (command.getAction() == CommandAmbulance.ACTION_LOAD + && command.isBroadcast()) { + this.priorityHumans.add(command.getTargetID()); + this.targetHumans.add(command.getTargetID()); + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(MessageReport.class)) { + MessageReport report = (MessageReport) message; + AmbulanceTeamInfo info = this.ambulanceTeamInfoMap + .get(report.getSenderID()); + if (info != null && report.isDone()) { + info.canNewAction = true; + this.priorityHumans.remove(info.target); + this.targetHumans.remove(info.target); + info.target = null; + this.ambulanceTeamInfoMap.put(info.agentID, info); + } + } + return this; + } + + + private Map + convert(Map map) { + Map result = new HashMap<>(); + for (EntityID id : map.keySet()) { + AmbulanceTeamInfo info = map.get(id); + if (info != null && info.target != null) { + result.put(id, info.target); + } + } + return result; + } + + + private List + getActionAgents(Map map) { + List result = new ArrayList<>(); + for (StandardEntity entity : this.worldInfo + .getEntitiesOfType(StandardEntityURN.POLICE_FORCE)) { + AmbulanceTeamInfo info = map.get(entity.getID()); + if (info != null && info.canNewAction + && ((AmbulanceTeam) entity).isPositionDefined()) { + result.add(entity); + } + } + return result; + } + + + private AmbulanceTeamInfo update(AmbulanceTeamInfo info, + MessageAmbulanceTeam message) { + if (message.isBuriednessDefined() && message.getBuriedness() > 0) { + info.canNewAction = false; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + return info; + } + if (message.getAction() == MessageAmbulanceTeam.ACTION_REST) { + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } else if (message.getAction() == MessageAmbulanceTeam.ACTION_MOVE) { + if (message.getTargetID() != null) { + StandardEntity entity = this.worldInfo.getEntity(message.getTargetID()); + if (entity != null) { + if (entity instanceof Area) { + if (entity.getStandardURN() == REFUGE) { + info.canNewAction = false; + return info; + } + StandardEntity targetEntity = this.worldInfo.getEntity(info.target); + if (targetEntity != null) { + if (targetEntity instanceof Human) { + targetEntity = this.worldInfo.getPosition((Human) targetEntity); + if (targetEntity == null) { + this.priorityHumans.remove(info.target); + this.targetHumans.remove(info.target); + info.canNewAction = true; + info.target = null; + return info; + } + } + if (targetEntity.getID().getValue() == entity.getID() + .getValue()) { + info.canNewAction = false; + } else { + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } + } else { + info.canNewAction = true; + info.target = null; + } + return info; + } else if (entity instanceof Human) { + if (entity.getID().getValue() == info.target.getValue()) { + info.canNewAction = false; + } else { + info.canNewAction = true; + this.targetHumans.add(info.target); + this.targetHumans.add(entity.getID()); + info.target = null; + } + return info; + } + } + } + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } else if (message.getAction() == MessageAmbulanceTeam.ACTION_RESCUE) { + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } else if (message.getAction() == MessageAmbulanceTeam.ACTION_LOAD) { + info.canNewAction = false; + } else if (message.getAction() == MessageAmbulanceTeam.ACTION_UNLOAD) { + info.canNewAction = true; + this.priorityHumans.remove(info.target); + this.targetHumans.remove(info.target); + info.target = null; + } + return info; + } + + private class AmbulanceTeamInfo { + + EntityID agentID; + EntityID target; + boolean canNewAction; + int commandTime; + + AmbulanceTeamInfo(EntityID id) { + agentID = id; + target = null; + canNewAction = true; + commandTime = -1; + } + } + + private class DistanceSorter implements Comparator { + + private StandardEntity reference; + private WorldInfo worldInfo; + + DistanceSorter(WorldInfo wi, StandardEntity reference) { + this.reference = reference; + this.worldInfo = wi; + } + + + public int compare(StandardEntity a, StandardEntity b) { + int d1 = this.worldInfo.getDistance(this.reference, a); + int d2 = this.worldInfo.getDistance(this.reference, b); + return d1 - d2; + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultBuildingDetector.java b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultBuildingDetector.java new file mode 100644 index 0000000..a266d8a --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultBuildingDetector.java @@ -0,0 +1,209 @@ +package adf_core_python.impl.module.complex; + +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.Clustering; +import adf_core_python.core.component.module.complex.BuildingDetector; +import rescuecore2.misc.geometry.Vector2D; +import rescuecore2.standard.entities.Building; +import rescuecore2.standard.entities.StandardEntity; +import rescuecore2.standard.entities.StandardEntityURN; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +public class DefaultBuildingDetector extends BuildingDetector { + + private EntityID result; + + private Clustering clustering; + + public DefaultBuildingDetector(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + switch (si.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.clustering = moduleManager.getModule( + "DefaultBuildingDetector.Clustering", + "adf_core_python_core_python.impl.module.algorithm.KMeansClustering"); + break; + } + registerModule(this.clustering); + } + + + @Override + public BuildingDetector updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + + return this; + } + + + @Override + public BuildingDetector calc() { + this.result = this.calcTargetInCluster(); + if (this.result == null) { + this.result = this.calcTargetInWorld(); + } + return this; + } + + + private EntityID calcTargetInCluster() { + int clusterIndex = this.clustering.getClusterIndex(this.agentInfo.getID()); + Collection elements = this.clustering + .getClusterEntities(clusterIndex); + if (elements == null || elements.isEmpty()) { + return null; + } + StandardEntity me = this.agentInfo.me(); + List agents = new ArrayList<>( + this.worldInfo.getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE)); + Set fireBuildings = new HashSet<>(); + for (StandardEntity entity : elements) { + if (entity instanceof Building && ((Building) entity).isOnFire()) { + fireBuildings.add(entity); + } + } + for (StandardEntity entity : fireBuildings) { + if (agents.isEmpty()) { + break; + } else if (agents.size() == 1) { + if (agents.get(0).getID().getValue() == me.getID().getValue()) { + return entity.getID(); + } + break; + } + agents.sort(new DistanceSorter(this.worldInfo, entity)); + StandardEntity a0 = agents.get(0); + StandardEntity a1 = agents.get(1); + + if (me.getID().getValue() == a0.getID().getValue() + || me.getID().getValue() == a1.getID().getValue()) { + return entity.getID(); + } else { + agents.remove(a0); + agents.remove(a1); + } + } + return null; + } + + + private EntityID calcTargetInWorld() { + Collection entities = this.worldInfo.getEntitiesOfType( + StandardEntityURN.BUILDING, StandardEntityURN.GAS_STATION, + StandardEntityURN.AMBULANCE_CENTRE, StandardEntityURN.FIRE_STATION, + StandardEntityURN.POLICE_OFFICE); + StandardEntity me = this.agentInfo.me(); + List agents = new ArrayList<>( + worldInfo.getEntitiesOfType(StandardEntityURN.FIRE_BRIGADE)); + Set fireBuildings = new HashSet<>(); + for (StandardEntity entity : entities) { + if (((Building) entity).isOnFire()) { + fireBuildings.add(entity); + } + } + for (StandardEntity entity : fireBuildings) { + if (agents.isEmpty()) { + break; + } else if (agents.size() == 1) { + if (agents.get(0).getID().getValue() == me.getID().getValue()) { + return entity.getID(); + } + break; + } + agents.sort(new DistanceSorter(this.worldInfo, entity)); + StandardEntity a0 = agents.get(0); + StandardEntity a1 = agents.get(1); + + if (me.getID().getValue() == a0.getID().getValue() + || me.getID().getValue() == a1.getID().getValue()) { + return entity.getID(); + } else { + agents.remove(a0); + agents.remove(a1); + } + } + return null; + } + + + @Override + public EntityID getTarget() { + return this.result; + } + + + @Override + public BuildingDetector precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + return this; + } + + + @Override + public BuildingDetector resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + return this; + } + + + @Override + public BuildingDetector preparate() { + super.preparate(); + if (this.getCountPrecompute() >= 2) { + return this; + } + return this; + } + + + @SuppressWarnings("unused") + private double getAngle(Vector2D v1, Vector2D v2) { + double flag = (v1.getX() * v2.getY()) - (v1.getY() * v2.getX()); + double angle = Math.acos(((v1.getX() * v2.getX()) + (v1.getY() * v2.getY())) + / (v1.getLength() * v2.getLength())); + if (flag > 0) { + return angle; + } + if (flag < 0) { + return -1 * angle; + } + return 0.0D; + } + + private class DistanceSorter implements Comparator { + + private StandardEntity reference; + private WorldInfo worldInfo; + + DistanceSorter(WorldInfo wi, StandardEntity reference) { + this.reference = reference; + this.worldInfo = wi; + } + + + public int compare(StandardEntity a, StandardEntity b) { + int d1 = this.worldInfo.getDistance(this.reference, a); + int d2 = this.worldInfo.getDistance(this.reference, b); + return d1 - d2; + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultFireTargetAllocator.java b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultFireTargetAllocator.java new file mode 100644 index 0000000..1d3224f --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultFireTargetAllocator.java @@ -0,0 +1,345 @@ +package adf_core_python.impl.module.complex; + +import adf.core.agent.communication.standard.bundle.MessageUtil; +import adf.core.agent.communication.standard.bundle.centralized.CommandFire; +import adf.core.agent.communication.standard.bundle.centralized.MessageReport; +import adf.core.agent.communication.standard.bundle.information.MessageCivilian; +import adf.core.agent.communication.standard.bundle.information.MessageFireBrigade; +import adf.core.agent.communication.standard.bundle.information.MessagePoliceForce; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf.core.component.communication.CommunicationMessage; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.FireTargetAllocator; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +import static rescuecore2.standard.entities.StandardEntityURN.REFUGE; + +public class DefaultFireTargetAllocator extends FireTargetAllocator { + + private Collection priorityHumans; + private Collection targetHumans; + + private Map fireBrigadeInfoMap; + + public DefaultFireTargetAllocator(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.priorityHumans = new HashSet<>(); + this.targetHumans = new HashSet<>(); + this.fireBrigadeInfoMap = new HashMap<>(); + } + + + @Override + public FireTargetAllocator resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + for (EntityID id : this.worldInfo + .getEntityIDsOfType(StandardEntityURN.FIRE_BRIGADE)) { + this.fireBrigadeInfoMap.put(id, new FireBrigadeInfo(id)); + } + return this; + } + + + @Override + public FireTargetAllocator preparate() { + super.preparate(); + if (this.getCountPrecompute() >= 2) { + return this; + } + for (EntityID id : this.worldInfo + .getEntityIDsOfType(StandardEntityURN.AMBULANCE_TEAM)) { + this.fireBrigadeInfoMap.put(id, new FireBrigadeInfo(id)); + } + return this; + } + + + @Override + public Map getResult() { + return this.convert(this.fireBrigadeInfoMap); + } + + + @Override + public FireTargetAllocator calc() { + List agents = this.getActionAgents(this.fireBrigadeInfoMap); + Collection removes = new ArrayList<>(); + int currentTime = this.agentInfo.getTime(); + for (EntityID target : this.priorityHumans) { + if (agents.size() > 0) { + StandardEntity targetEntity = this.worldInfo.getEntity(target); + if (targetEntity != null && targetEntity instanceof Human + && ((Human) targetEntity).isPositionDefined()) { + agents.sort(new DistanceSorter(this.worldInfo, targetEntity)); + StandardEntity result = agents.get(0); + agents.remove(0); + FireBrigadeInfo info = this.fireBrigadeInfoMap.get(result.getID()); + if (info != null) { + info.canNewAction = false; + info.target = target; + info.commandTime = currentTime; + this.fireBrigadeInfoMap.put(result.getID(), info); + removes.add(target); + } + } + } + } + this.priorityHumans.removeAll(removes); + removes.clear(); + for (EntityID target : this.targetHumans) { + if (agents.size() > 0) { + StandardEntity targetEntity = this.worldInfo.getEntity(target); + if (targetEntity != null && targetEntity instanceof Human + && ((Human) targetEntity).isPositionDefined()) { + agents.sort(new DistanceSorter(this.worldInfo, targetEntity)); + StandardEntity result = agents.get(0); + agents.remove(0); + FireBrigadeInfo info = this.fireBrigadeInfoMap.get(result.getID()); + if (info != null) { + info.canNewAction = false; + info.target = target; + info.commandTime = currentTime; + this.fireBrigadeInfoMap.put(result.getID(), info); + removes.add(target); + } + } + } + } + this.targetHumans.removeAll(removes); + return this; + } + + + @Override + public FireTargetAllocator updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + int currentTime = this.agentInfo.getTime(); + for (CommunicationMessage message : messageManager + .getReceivedMessageList()) { + Class messageClass = message.getClass(); + if (messageClass == MessageCivilian.class) { + MessageCivilian mc = (MessageCivilian) message; + MessageUtil.reflectMessage(this.worldInfo, mc); + if (mc.isBuriednessDefined() && mc.getBuriedness() > 0) { + this.targetHumans.add(mc.getAgentID()); + } else { + this.priorityHumans.remove(mc.getAgentID()); + this.targetHumans.remove(mc.getAgentID()); + } + } else if (messageClass == MessageFireBrigade.class) { + MessageFireBrigade mfb = (MessageFireBrigade) message; + MessageUtil.reflectMessage(this.worldInfo, mfb); + if (mfb.isBuriednessDefined() && mfb.getBuriedness() > 0) { + this.priorityHumans.add(mfb.getAgentID()); + } else { + this.priorityHumans.remove(mfb.getAgentID()); + this.targetHumans.remove(mfb.getAgentID()); + } + } else if (messageClass == MessagePoliceForce.class) { + MessagePoliceForce mpf = (MessagePoliceForce) message; + MessageUtil.reflectMessage(this.worldInfo, mpf); + if (mpf.isBuriednessDefined() && mpf.getBuriedness() > 0) { + this.priorityHumans.add(mpf.getAgentID()); + } else { + this.priorityHumans.remove(mpf.getAgentID()); + this.targetHumans.remove(mpf.getAgentID()); + } + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(MessageFireBrigade.class)) { + MessageFireBrigade mat = (MessageFireBrigade) message; + MessageUtil.reflectMessage(this.worldInfo, mat); + if (mat.isBuriednessDefined() && mat.getBuriedness() > 0) { + this.priorityHumans.add(mat.getAgentID()); + } else { + this.priorityHumans.remove(mat.getAgentID()); + this.targetHumans.remove(mat.getAgentID()); + } + FireBrigadeInfo info = this.fireBrigadeInfoMap.get(mat.getAgentID()); + if (info == null) { + info = new FireBrigadeInfo(mat.getAgentID()); + } + if (currentTime >= info.commandTime + 2) { + this.fireBrigadeInfoMap.put(mat.getAgentID(), this.update(info, mat)); + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(CommandFire.class)) { + CommandFire command = (CommandFire) message; + if (command.getAction() == CommandFire.ACTION_RESCUE + && command.isBroadcast()) { + this.priorityHumans.add(command.getTargetID()); + this.targetHumans.add(command.getTargetID()); + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(MessageReport.class)) { + MessageReport report = (MessageReport) message; + FireBrigadeInfo info = this.fireBrigadeInfoMap.get(report.getSenderID()); + if (info != null && report.isDone()) { + info.canNewAction = true; + this.priorityHumans.remove(info.target); + this.targetHumans.remove(info.target); + info.target = null; + this.fireBrigadeInfoMap.put(info.agentID, info); + } + } + return this; + } + + + private Map convert(Map map) { + Map result = new HashMap<>(); + for (EntityID id : map.keySet()) { + FireBrigadeInfo info = map.get(id); + if (info != null && info.target != null) { + result.put(id, info.target); + } + } + return result; + } + + + private List + getActionAgents(Map map) { + List result = new ArrayList<>(); + for (StandardEntity entity : this.worldInfo + .getEntitiesOfType(StandardEntityURN.POLICE_FORCE)) { + FireBrigadeInfo info = map.get(entity.getID()); + if (info != null && info.canNewAction + && ((FireBrigade) entity).isPositionDefined()) { + result.add(entity); + } + } + return result; + } + + + private FireBrigadeInfo update(FireBrigadeInfo info, + MessageFireBrigade message) { + if (message.isBuriednessDefined() && message.getBuriedness() > 0) { + info.canNewAction = false; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + return info; + } + if (message.getAction() == MessageFireBrigade.ACTION_REST) { + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } else if (message.getAction() == MessageFireBrigade.ACTION_MOVE) { + if (message.getTargetID() != null) { + StandardEntity entity = this.worldInfo.getEntity(message.getTargetID()); + if (entity != null) { + if (entity instanceof Area) { + if (entity.getStandardURN() == REFUGE) { + info.canNewAction = false; + return info; + } + StandardEntity targetEntity = this.worldInfo.getEntity(info.target); + if (targetEntity != null) { + if (targetEntity instanceof Human) { + targetEntity = this.worldInfo.getPosition((Human) targetEntity); + if (targetEntity == null) { + this.priorityHumans.remove(info.target); + this.targetHumans.remove(info.target); + info.canNewAction = true; + info.target = null; + return info; + } + } + if (targetEntity.getID().getValue() == entity.getID() + .getValue()) { + info.canNewAction = false; + } else { + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } + } else { + info.canNewAction = true; + info.target = null; + } + return info; + } else if (entity instanceof Human) { + if (entity.getID().getValue() == info.target.getValue()) { + info.canNewAction = false; + } else { + info.canNewAction = true; + this.targetHumans.add(info.target); + this.targetHumans.add(entity.getID()); + info.target = null; + } + return info; + } + } + } + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } else if (message.getAction() == MessageFireBrigade.ACTION_RESCUE) { + info.canNewAction = true; + if (info.target != null) { + this.targetHumans.add(info.target); + info.target = null; + } + } + return info; + } + + private class FireBrigadeInfo { + + EntityID agentID; + EntityID target; + boolean canNewAction; + int commandTime; + + FireBrigadeInfo(EntityID id) { + agentID = id; + target = null; + canNewAction = true; + commandTime = -1; + } + } + + private class DistanceSorter implements Comparator { + + private StandardEntity reference; + private WorldInfo worldInfo; + + DistanceSorter(WorldInfo wi, StandardEntity reference) { + this.reference = reference; + this.worldInfo = wi; + } + + + public int compare(StandardEntity a, StandardEntity b) { + int d1 = this.worldInfo.getDistance(this.reference, a); + int d2 = this.worldInfo.getDistance(this.reference, b); + return d1 - d2; + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultHumanDetector.java b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultHumanDetector.java new file mode 100644 index 0000000..21d0262 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultHumanDetector.java @@ -0,0 +1,252 @@ +package adf_core_python.impl.module.complex; + +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.Clustering; +import adf_core_python.core.component.module.complex.HumanDetector; +import rescuecore2.standard.entities.Area; +import rescuecore2.standard.entities.Human; +import rescuecore2.standard.entities.StandardEntity; +import rescuecore2.standard.entities.StandardEntityURN; +import rescuecore2.worldmodel.EntityID; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; + +import static rescuecore2.standard.entities.StandardEntityURN.*; + +public class DefaultHumanDetector extends HumanDetector { + + private Clustering clustering; + + private EntityID result; + + public DefaultHumanDetector(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + + this.result = null; + + switch (scenarioInfo.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.clustering = moduleManager.getModule( + "DefaultHumanDetector.Clustering", + "adf_core_python.impl.module.algorithm.KMeansClustering"); + break; + } + registerModule(this.clustering); + } + + + @Override + public HumanDetector updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() > 1) { + return this; + } + + return this; + } + + + @Override + public HumanDetector calc() { + Human transportHuman = this.agentInfo.someoneOnBoard(); + if (transportHuman != null) { + this.result = transportHuman.getID(); + return this; + } + if (this.result != null) { + Human target = (Human) this.worldInfo.getEntity(this.result); + if (target != null) { + if (!target.isHPDefined() || target.getHP() == 0) { + this.result = null; + } else if (!target.isPositionDefined()) { + this.result = null; + } else { + StandardEntity position = this.worldInfo.getPosition(target); + if (position != null) { + StandardEntityURN positionURN = position.getStandardURN(); + if (positionURN == REFUGE || positionURN == AMBULANCE_TEAM) { + this.result = null; + } + } + } + } + } + if (this.result == null) { + if (clustering == null) { + this.result = this.calcTargetInWorld(); + return this; + } + this.result = this.calcTargetInCluster(clustering); + if (this.result == null) { + this.result = this.calcTargetInWorld(); + } + } + return this; + } + + + private EntityID calcTargetInCluster(Clustering clustering) { + int clusterIndex = clustering.getClusterIndex(this.agentInfo.getID()); + Collection< + StandardEntity> elements = clustering.getClusterEntities(clusterIndex); + if (elements == null || elements.isEmpty()) { + return null; + } + + List rescueTargets = new ArrayList<>(); + List loadTargets = new ArrayList<>(); + for (StandardEntity next : this.worldInfo.getEntitiesOfType(AMBULANCE_TEAM, + FIRE_BRIGADE, POLICE_FORCE)) { + Human h = (Human) next; + if (this.agentInfo.getID().getValue() == h.getID().getValue()) { + continue; + } + StandardEntity positionEntity = this.worldInfo.getPosition(h); + if (positionEntity != null && elements.contains(positionEntity) + || elements.contains(h)) { + if (h.isHPDefined() && h.isBuriednessDefined() && h.getHP() > 0 + && h.getBuriedness() > 0) { + rescueTargets.add(h); + } + } + } + for (StandardEntity next : this.worldInfo.getEntitiesOfType(CIVILIAN)) { + Human h = (Human) next; + StandardEntity positionEntity = this.worldInfo.getPosition(h); + if (positionEntity != null && positionEntity instanceof Area) { + if (elements.contains(positionEntity)) { + if (h.isHPDefined() && h.getHP() > 0) { + if (h.isBuriednessDefined() && h.getBuriedness() > 0) { + rescueTargets.add(h); + } else { + if (h.isDamageDefined() && h.getDamage() > 0 + && positionEntity.getStandardURN() != REFUGE) { + loadTargets.add(h); + } + } + } + } + } + } + if (rescueTargets.size() > 0) { + rescueTargets + .sort(new DistanceSorter(this.worldInfo, this.agentInfo.me())); + return rescueTargets.get(0).getID(); + } + if (loadTargets.size() > 0) { + loadTargets.sort(new DistanceSorter(this.worldInfo, this.agentInfo.me())); + return loadTargets.get(0).getID(); + } + return null; + } + + + private EntityID calcTargetInWorld() { + List rescueTargets = new ArrayList<>(); + List loadTargets = new ArrayList<>(); + for (StandardEntity next : this.worldInfo.getEntitiesOfType(AMBULANCE_TEAM, + FIRE_BRIGADE, POLICE_FORCE)) { + Human h = (Human) next; + if (this.agentInfo.getID().getValue() != h.getID().getValue()) { + StandardEntity positionEntity = this.worldInfo.getPosition(h); + if (positionEntity != null && h.isHPDefined() + && h.isBuriednessDefined()) { + if (h.getHP() > 0 && h.getBuriedness() > 0) { + rescueTargets.add(h); + } + } + } + } + for (StandardEntity next : this.worldInfo.getEntitiesOfType(CIVILIAN)) { + Human h = (Human) next; + StandardEntity positionEntity = this.worldInfo.getPosition(h); + if (positionEntity != null && positionEntity instanceof Area) { + if (h.isHPDefined() && h.getHP() > 0) { + if (h.isBuriednessDefined() && h.getBuriedness() > 0) { + rescueTargets.add(h); + } else { + if (h.isDamageDefined() && h.getDamage() > 0 + && positionEntity.getStandardURN() != REFUGE) { + loadTargets.add(h); + } + } + } + } + } + if (rescueTargets.size() > 0) { + rescueTargets + .sort(new DistanceSorter(this.worldInfo, this.agentInfo.me())); + return rescueTargets.get(0).getID(); + } + if (loadTargets.size() > 0) { + loadTargets.sort(new DistanceSorter(this.worldInfo, this.agentInfo.me())); + return loadTargets.get(0).getID(); + } + return null; + } + + + @Override + public EntityID getTarget() { + return this.result; + } + + + @Override + public HumanDetector precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + return this; + } + + + @Override + public HumanDetector resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + return this; + } + + + @Override + public HumanDetector preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + return this; + } + + private class DistanceSorter implements Comparator { + + private StandardEntity reference; + private WorldInfo worldInfo; + + DistanceSorter(WorldInfo wi, StandardEntity reference) { + this.reference = reference; + this.worldInfo = wi; + } + + + public int compare(StandardEntity a, StandardEntity b) { + int d1 = this.worldInfo.getDistance(this.reference, a); + int d2 = this.worldInfo.getDistance(this.reference, b); + return d1 - d2; + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultPoliceTargetAllocator.java b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultPoliceTargetAllocator.java new file mode 100644 index 0000000..688c510 --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultPoliceTargetAllocator.java @@ -0,0 +1,323 @@ +package adf_core_python.impl.module.complex; + +import adf.core.agent.communication.standard.bundle.MessageUtil; +import adf.core.agent.communication.standard.bundle.centralized.CommandPolice; +import adf.core.agent.communication.standard.bundle.centralized.MessageReport; +import adf.core.agent.communication.standard.bundle.information.MessagePoliceForce; +import adf.core.agent.communication.standard.bundle.information.MessageRoad; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf.core.component.communication.CommunicationMessage; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.complex.PoliceTargetAllocator; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +import static rescuecore2.standard.entities.StandardEntityURN.*; + +public class DefaultPoliceTargetAllocator extends PoliceTargetAllocator { + + private Collection priorityAreas; + private Collection targetAreas; + + private Map agentInfoMap; + + public DefaultPoliceTargetAllocator(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + this.priorityAreas = new HashSet<>(); + this.targetAreas = new HashSet<>(); + this.agentInfoMap = new HashMap<>(); + } + + + @Override + public PoliceTargetAllocator resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + for (EntityID id : this.worldInfo + .getEntityIDsOfType(StandardEntityURN.POLICE_FORCE)) { + this.agentInfoMap.put(id, new PoliceForceInfo(id)); + } + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE, BUILDING, + GAS_STATION)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.targetAreas.add(id); + } + } + } + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.priorityAreas.add(id); + } + } + } + return this; + } + + + @Override + public PoliceTargetAllocator preparate() { + super.preparate(); + if (this.getCountPrecompute() >= 2) { + return this; + } + for (EntityID id : this.worldInfo + .getEntityIDsOfType(StandardEntityURN.POLICE_FORCE)) { + this.agentInfoMap.put(id, new PoliceForceInfo(id)); + } + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE, BUILDING, + GAS_STATION)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.targetAreas.add(id); + } + } + } + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.priorityAreas.add(id); + } + } + } + return this; + } + + + @Override + public Map getResult() { + return this.convert(this.agentInfoMap); + } + + + @Override + public PoliceTargetAllocator calc() { + List agents = this.getActionAgents(this.agentInfoMap); + Collection removes = new ArrayList<>(); + int currentTime = this.agentInfo.getTime(); + for (EntityID target : this.priorityAreas) { + if (agents.size() > 0) { + StandardEntity targetEntity = this.worldInfo.getEntity(target); + if (targetEntity != null) { + agents.sort(new DistanceSorter(this.worldInfo, targetEntity)); + StandardEntity result = agents.get(0); + agents.remove(0); + PoliceForceInfo info = this.agentInfoMap.get(result.getID()); + if (info != null) { + info.canNewAction = false; + info.target = target; + info.commandTime = currentTime; + this.agentInfoMap.put(result.getID(), info); + removes.add(target); + } + } + } + } + this.priorityAreas.removeAll(removes); + List areas = new ArrayList<>(); + for (EntityID target : this.targetAreas) { + StandardEntity targetEntity = this.worldInfo.getEntity(target); + if (targetEntity != null) { + areas.add(targetEntity); + } + } + for (StandardEntity agent : agents) { + if (areas.size() > 0) { + areas.sort(new DistanceSorter(this.worldInfo, agent)); + StandardEntity result = areas.get(0); + areas.remove(0); + this.targetAreas.remove(result.getID()); + PoliceForceInfo info = this.agentInfoMap.get(agent.getID()); + if (info != null) { + info.canNewAction = false; + info.target = result.getID(); + info.commandTime = currentTime; + this.agentInfoMap.put(agent.getID(), info); + } + } + } + return this; + } + + + @Override + public PoliceTargetAllocator updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + int currentTime = this.agentInfo.getTime(); + for (CommunicationMessage message : messageManager + .getReceivedMessageList(MessageRoad.class)) { + MessageRoad mpf = (MessageRoad) message; + MessageUtil.reflectMessage(this.worldInfo, mpf); + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(MessagePoliceForce.class)) { + MessagePoliceForce mpf = (MessagePoliceForce) message; + MessageUtil.reflectMessage(this.worldInfo, mpf); + PoliceForceInfo info = this.agentInfoMap.get(mpf.getAgentID()); + if (info == null) { + info = new PoliceForceInfo(mpf.getAgentID()); + } + if (currentTime >= info.commandTime + 2) { + this.agentInfoMap.put(mpf.getAgentID(), this.update(info, mpf)); + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(CommandPolice.class)) { + CommandPolice command = (CommandPolice) message; + if (command.getAction() == CommandPolice.ACTION_CLEAR + && command.isBroadcast()) { + this.priorityAreas.add(command.getTargetID()); + this.targetAreas.add(command.getTargetID()); + } + } + for (CommunicationMessage message : messageManager + .getReceivedMessageList(MessageReport.class)) { + MessageReport report = (MessageReport) message; + PoliceForceInfo info = this.agentInfoMap.get(report.getSenderID()); + if (info != null && report.isDone()) { + info.canNewAction = true; + this.priorityAreas.remove(info.target); + this.targetAreas.remove(info.target); + info.target = null; + this.agentInfoMap.put(info.agentID, info); + } + } + return this; + } + + + private PoliceForceInfo update(PoliceForceInfo info, + MessagePoliceForce message) { + if (message.isBuriednessDefined() && message.getBuriedness() > 0) { + info.canNewAction = false; + if (info.target != null) { + this.targetAreas.add(info.target); + info.target = null; + } + return info; + } + if (message.getAction() == MessagePoliceForce.ACTION_REST) { + info.canNewAction = true; + if (info.target != null) { + this.targetAreas.add(info.target); + info.target = null; + } + } else if (message.getAction() == MessagePoliceForce.ACTION_MOVE) { + if (message.getTargetID() != null) { + StandardEntity entity = this.worldInfo.getEntity(message.getTargetID()); + if (entity != null && entity instanceof Area) { + if (info.target != null) { + StandardEntity targetEntity = this.worldInfo.getEntity(info.target); + if (targetEntity != null && targetEntity instanceof Area) { + if (message.getTargetID().getValue() == info.target.getValue()) { + info.canNewAction = false; + } else { + info.canNewAction = true; + this.targetAreas.add(info.target); + info.target = null; + } + } else { + info.canNewAction = true; + info.target = null; + } + } else { + info.canNewAction = true; + } + } else { + info.canNewAction = true; + if (info.target != null) { + this.targetAreas.add(info.target); + info.target = null; + } + } + } else { + info.canNewAction = true; + if (info.target != null) { + this.targetAreas.add(info.target); + info.target = null; + } + } + } else if (message.getAction() == MessagePoliceForce.ACTION_CLEAR) { + info.canNewAction = false; + } + return info; + } + + + private List + getActionAgents(Map infoMap) { + List result = new ArrayList<>(); + for (StandardEntity entity : this.worldInfo + .getEntitiesOfType(StandardEntityURN.POLICE_FORCE)) { + PoliceForceInfo info = infoMap.get(entity.getID()); + if (info != null && info.canNewAction + && ((PoliceForce) entity).isPositionDefined()) { + result.add(entity); + } + } + return result; + } + + + private Map + convert(Map infoMap) { + Map result = new HashMap<>(); + for (EntityID id : infoMap.keySet()) { + PoliceForceInfo info = infoMap.get(id); + if (info != null && info.target != null) { + result.put(id, info.target); + } + } + return result; + } + + private class PoliceForceInfo { + + EntityID agentID; + EntityID target; + boolean canNewAction; + int commandTime; + + PoliceForceInfo(EntityID id) { + agentID = id; + target = null; + canNewAction = true; + commandTime = -1; + } + } + + private class DistanceSorter implements Comparator { + + private StandardEntity reference; + private WorldInfo worldInfo; + + DistanceSorter(WorldInfo wi, StandardEntity reference) { + this.reference = reference; + this.worldInfo = wi; + } + + + public int compare(StandardEntity a, StandardEntity b) { + int d1 = this.worldInfo.getDistance(this.reference, a); + int d2 = this.worldInfo.getDistance(this.reference, b); + return d1 - d2; + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultRoadDetector.java b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultRoadDetector.java new file mode 100644 index 0000000..277342c --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultRoadDetector.java @@ -0,0 +1,362 @@ +package adf_core_python.impl.module.complex; + +import adf.core.agent.communication.standard.bundle.MessageUtil; +import adf.core.agent.communication.standard.bundle.centralized.CommandPolice; +import adf.core.agent.communication.standard.bundle.information.MessageAmbulanceTeam; +import adf.core.agent.communication.standard.bundle.information.MessageFireBrigade; +import adf.core.agent.communication.standard.bundle.information.MessagePoliceForce; +import adf.core.agent.communication.standard.bundle.information.MessageRoad; +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf.core.component.communication.CommunicationMessage; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import adf_core_python.core.component.module.complex.RoadDetector; +import rescuecore2.standard.entities.*; +import rescuecore2.worldmodel.EntityID; + +import java.util.*; + +import static rescuecore2.standard.entities.StandardEntityURN.*; + +public class DefaultRoadDetector extends RoadDetector { + + private Set targetAreas; + private Set priorityRoads; + + private PathPlanning pathPlanning; + + private EntityID result; + + public DefaultRoadDetector(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + switch (scenarioInfo.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + this.pathPlanning = moduleManager.getModule( + "DefaultRoadDetector.PathPlanning", + "adf_core_python_core_python.impl.module.algorithm.DijkstraPathPlanning"); + break; + } + registerModule(this.pathPlanning); + this.result = null; + } + + + @Override + public RoadDetector calc() { + if (this.result == null) { + EntityID positionID = this.agentInfo.getPosition(); + if (this.targetAreas.contains(positionID)) { + this.result = positionID; + return this; + } + List removeList = new ArrayList<>(this.priorityRoads.size()); + for (EntityID id : this.priorityRoads) { + if (!this.targetAreas.contains(id)) { + removeList.add(id); + } + } + this.priorityRoads.removeAll(removeList); + if (this.priorityRoads.size() > 0) { + this.pathPlanning.setFrom(positionID); + this.pathPlanning.setDestination(this.targetAreas); + List path = this.pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + this.result = path.get(path.size() - 1); + } + return this; + } + + this.pathPlanning.setFrom(positionID); + this.pathPlanning.setDestination(this.targetAreas); + List path = this.pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + this.result = path.get(path.size() - 1); + } + } + return this; + } + + + @Override + public EntityID getTarget() { + return this.result; + } + + + @Override + public RoadDetector precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + return this; + } + + + @Override + public RoadDetector resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.targetAreas = new HashSet<>(); + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE, BUILDING, + GAS_STATION)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.targetAreas.add(id); + } + } + } + this.priorityRoads = new HashSet<>(); + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.priorityRoads.add(id); + } + } + } + return this; + } + + + @Override + public RoadDetector preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.targetAreas = new HashSet<>(); + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE, BUILDING, + GAS_STATION)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.targetAreas.add(id); + } + } + } + this.priorityRoads = new HashSet<>(); + for (StandardEntity e : this.worldInfo.getEntitiesOfType(REFUGE)) { + for (EntityID id : ((Building) e).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.priorityRoads.add(id); + } + } + } + return this; + } + + + @Override + public RoadDetector updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + if (this.result != null) { + if (this.agentInfo.getPosition().equals(this.result)) { + StandardEntity entity = this.worldInfo.getEntity(this.result); + if (entity instanceof Building) { + this.result = null; + } else if (entity instanceof Road) { + Road road = (Road) entity; + if (!road.isBlockadesDefined() || road.getBlockades().isEmpty()) { + this.targetAreas.remove(this.result); + this.result = null; + } + } + } + } + Set changedEntities = this.worldInfo.getChanged() + .getChangedEntities(); + for (CommunicationMessage message : messageManager + .getReceivedMessageList()) { + Class messageClass = message.getClass(); + if (messageClass == MessageAmbulanceTeam.class) { + this.reflectMessage((MessageAmbulanceTeam) message); + } else if (messageClass == MessageFireBrigade.class) { + this.reflectMessage((MessageFireBrigade) message); + } else if (messageClass == MessageRoad.class) { + this.reflectMessage((MessageRoad) message, changedEntities); + } else if (messageClass == MessagePoliceForce.class) { + this.reflectMessage((MessagePoliceForce) message); + } else if (messageClass == CommandPolice.class) { + this.reflectMessage((CommandPolice) message); + } + } + for (EntityID id : this.worldInfo.getChanged().getChangedEntities()) { + StandardEntity entity = this.worldInfo.getEntity(id); + if (entity instanceof Road) { + Road road = (Road) entity; + if (!road.isBlockadesDefined() || road.getBlockades().isEmpty()) { + this.targetAreas.remove(id); + } + } + } + return this; + } + + + private void reflectMessage(MessageRoad messageRoad, + Collection changedEntities) { + if (messageRoad.isBlockadeDefined() + && !changedEntities.contains(messageRoad.getBlockadeID())) { + MessageUtil.reflectMessage(this.worldInfo, messageRoad); + } + if (messageRoad.isPassable()) { + this.targetAreas.remove(messageRoad.getRoadID()); + } + } + + + private void reflectMessage(MessageAmbulanceTeam messageAmbulanceTeam) { + if (messageAmbulanceTeam.getPosition() == null) { + return; + } + if (messageAmbulanceTeam + .getAction() == MessageAmbulanceTeam.ACTION_RESCUE) { + StandardEntity position = this.worldInfo + .getEntity(messageAmbulanceTeam.getPosition()); + if (position != null && position instanceof Building) { + this.targetAreas.removeAll(((Building) position).getNeighbours()); + } + } else if (messageAmbulanceTeam + .getAction() == MessageAmbulanceTeam.ACTION_LOAD) { + StandardEntity position = this.worldInfo + .getEntity(messageAmbulanceTeam.getPosition()); + if (position != null && position instanceof Building) { + this.targetAreas.removeAll(((Building) position).getNeighbours()); + } + } else if (messageAmbulanceTeam + .getAction() == MessageAmbulanceTeam.ACTION_MOVE) { + if (messageAmbulanceTeam.getTargetID() == null) { + return; + } + StandardEntity target = this.worldInfo + .getEntity(messageAmbulanceTeam.getTargetID()); + if (target instanceof Building) { + for (EntityID id : ((Building) target).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.priorityRoads.add(id); + } + } + } else if (target instanceof Human) { + Human human = (Human) target; + if (human.isPositionDefined()) { + StandardEntity position = this.worldInfo.getPosition(human); + if (position instanceof Building) { + for (EntityID id : ((Building) position).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.priorityRoads.add(id); + } + } + } + } + } + } + } + + + private void reflectMessage(MessageFireBrigade messageFireBrigade) { + if (messageFireBrigade.getTargetID() == null) { + return; + } + if (messageFireBrigade.getAction() == MessageFireBrigade.ACTION_REFILL) { + StandardEntity target = this.worldInfo + .getEntity(messageFireBrigade.getTargetID()); + if (target instanceof Building) { + for (EntityID id : ((Building) target).getNeighbours()) { + StandardEntity neighbour = this.worldInfo.getEntity(id); + if (neighbour instanceof Road) { + this.priorityRoads.add(id); + } + } + } else if (target.getStandardURN() == HYDRANT) { + this.priorityRoads.add(target.getID()); + this.targetAreas.add(target.getID()); + } + } + } + + + private void reflectMessage(MessagePoliceForce messagePoliceForce) { + if (messagePoliceForce.getAction() == MessagePoliceForce.ACTION_CLEAR) { + if (messagePoliceForce.getAgentID().getValue() != this.agentInfo.getID() + .getValue()) { + if (messagePoliceForce.isTargetDefined()) { + EntityID targetID = messagePoliceForce.getTargetID(); + if (targetID == null) { + return; + } + StandardEntity entity = this.worldInfo.getEntity(targetID); + if (entity == null) { + return; + } + + if (entity instanceof Area) { + this.targetAreas.remove(targetID); + if (this.result != null + && this.result.getValue() == targetID.getValue()) { + if (this.agentInfo.getID().getValue() < messagePoliceForce + .getAgentID().getValue()) { + this.result = null; + } + } + } else if (entity.getStandardURN() == BLOCKADE) { + EntityID position = ((Blockade) entity).getPosition(); + this.targetAreas.remove(position); + if (this.result != null + && this.result.getValue() == position.getValue()) { + if (this.agentInfo.getID().getValue() < messagePoliceForce + .getAgentID().getValue()) { + this.result = null; + } + } + } + + } + } + } + } + + + private void reflectMessage(CommandPolice commandPolice) { + boolean flag = false; + if (commandPolice.isToIDDefined() && this.agentInfo.getID() + .getValue() == commandPolice.getToID().getValue()) { + flag = true; + } else if (commandPolice.isBroadcast()) { + flag = true; + } + if (flag && commandPolice.getAction() == CommandPolice.ACTION_CLEAR) { + if (commandPolice.getTargetID() == null) { + return; + } + StandardEntity target = this.worldInfo + .getEntity(commandPolice.getTargetID()); + if (target instanceof Area) { + this.priorityRoads.add(target.getID()); + this.targetAreas.add(target.getID()); + } else if (target.getStandardURN() == BLOCKADE) { + Blockade blockade = (Blockade) target; + if (blockade.isPositionDefined()) { + this.priorityRoads.add(blockade.getPosition()); + this.targetAreas.add(blockade.getPosition()); + } + } + } + } +} diff --git a/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultSearch.java b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultSearch.java new file mode 100644 index 0000000..c75c7ed --- /dev/null +++ b/java/lib/src/main/java/adf_core_python/impl/module/complex/DefaultSearch.java @@ -0,0 +1,164 @@ +package adf_core_python.impl.module.complex; + +import adf.core.agent.develop.DevelopData; +import adf.core.agent.info.ScenarioInfo; +import adf.core.agent.info.WorldInfo; +import adf_core_python.core.agent.communication.MessageManager; +import adf_core_python.core.agent.info.AgentInfo; +import adf_core_python.core.agent.module.ModuleManager; +import adf_core_python.core.agent.precompute.PrecomputeData; +import adf_core_python.core.component.module.algorithm.Clustering; +import adf_core_python.core.component.module.algorithm.PathPlanning; +import adf_core_python.core.component.module.complex.Search; +import rescuecore2.standard.entities.Building; +import rescuecore2.standard.entities.StandardEntity; +import rescuecore2.standard.entities.StandardEntityURN; +import rescuecore2.worldmodel.EntityID; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +import static rescuecore2.standard.entities.StandardEntityURN.*; + +public class DefaultSearch extends Search { + + private PathPlanning pathPlanning; + private Clustering clustering; + + private EntityID result; + private Collection unsearchedBuildingIDs; + + public DefaultSearch(AgentInfo ai, WorldInfo wi, ScenarioInfo si, ModuleManager moduleManager, DevelopData developData) { + super(ai, wi, si, moduleManager, developData); + + this.unsearchedBuildingIDs = new HashSet<>(); + + StandardEntityURN agentURN = ai.me().getStandardURN(); + switch (si.getMode()) { + case PRECOMPUTATION_PHASE: + case PRECOMPUTED: + case NON_PRECOMPUTE: + if (agentURN == AMBULANCE_TEAM) { + this.pathPlanning = moduleManager.getModule( + "DefaultSearch.PathPlanning.Ambulance", + "adf_core_python_core_python.impl.module.algorithm.DijkstraPathPlanning"); + this.clustering = moduleManager.getModule( + "DefaultSearch.Clustering.Ambulance", + "adf_core_python.impl.module.algorithm.KMeansClustering"); + } else if (agentURN == FIRE_BRIGADE) { + this.pathPlanning = moduleManager.getModule( + "DefaultSearch.PathPlanning.Fire", + "adf_core_python.impl.module.algorithm.DijkstraPathPlanning"); + this.clustering = moduleManager.getModule( + "DefaultSearch.Clustering.Fire", + "adf_core_python.impl.module.algorithm.KMeansClustering"); + } else if (agentURN == POLICE_FORCE) { + this.pathPlanning = moduleManager.getModule( + "DefaultSearch.PathPlanning.Police", + "adf_core_python.impl.module.algorithm.DijkstraPathPlanning"); + this.clustering = moduleManager.getModule( + "DefaultSearch.Clustering.Police", + "adf_core_python.impl.module.algorithm.KMeansClustering"); + } + break; + } + + registerModule(this.pathPlanning); + registerModule(this.clustering); + } + + + @Override + public Search updateInfo(MessageManager messageManager) { + super.updateInfo(messageManager); + if (this.getCountUpdateInfo() >= 2) { + return this; + } + + this.unsearchedBuildingIDs + .removeAll(this.worldInfo.getChanged().getChangedEntities()); + + if (this.unsearchedBuildingIDs.isEmpty()) { + this.reset(); + this.unsearchedBuildingIDs + .removeAll(this.worldInfo.getChanged().getChangedEntities()); + } + return this; + } + + + @Override + public Search calc() { + this.result = null; + this.pathPlanning.setFrom(this.agentInfo.getPosition()); + this.pathPlanning.setDestination(this.unsearchedBuildingIDs); + List path = this.pathPlanning.calc().getResult(); + if (path != null && path.size() > 0) { + this.result = path.get(path.size() - 1); + } + return this; + } + + + private void reset() { + this.unsearchedBuildingIDs.clear(); + + Collection clusterEntities = null; + if (this.clustering != null) { + int clusterIndex = this.clustering + .getClusterIndex(this.agentInfo.getID()); + clusterEntities = this.clustering.getClusterEntities(clusterIndex); + + } + if (clusterEntities != null && clusterEntities.size() > 0) { + for (StandardEntity entity : clusterEntities) { + if (entity instanceof Building && entity.getStandardURN() != REFUGE) { + this.unsearchedBuildingIDs.add(entity.getID()); + } + } + } else { + this.unsearchedBuildingIDs + .addAll(this.worldInfo.getEntityIDsOfType(BUILDING, GAS_STATION, + AMBULANCE_CENTRE, FIRE_STATION, POLICE_OFFICE)); + } + } + + + @Override + public EntityID getTarget() { + return this.result; + } + + + @Override + public Search precompute(PrecomputeData precomputeData) { + super.precompute(precomputeData); + if (this.getCountPrecompute() >= 2) { + return this; + } + return this; + } + + + @Override + public Search resume(PrecomputeData precomputeData) { + super.resume(precomputeData); + if (this.getCountResume() >= 2) { + return this; + } + this.worldInfo.requestRollback(); + return this; + } + + + @Override + public Search preparate() { + super.preparate(); + if (this.getCountPreparate() >= 2) { + return this; + } + this.worldInfo.requestRollback(); + return this; + } +}