Depois de fazer o dowload do código fonte dos projetos e abrir no Netbeans, começamos a analisar o código do DemoSOAR através da classe SimulationSOAR.java.
A classe NativeUtils, utilizada pela classe SimulationSOAR faz o gerencimento do carregamento do código nativo implementado em bibliotecas específicas para cada plataforma. Inicialmente, o classpath do java é apontado para a pasta atual da aplicação, então pegam-se as propriedades de sistema, como o nome do sistema operacional e a arquitetura do mesmo através do método System.getProperty(...). As bibliotecas nativas estão dentro do JAR, separadas em pastas relativas aos sitemas operacionais e arquitetura e são então copiadas de acordo com o SO/Arqutitetura atual, forma temporária para a pasta atual do projento, através do método NativeUtils.loadFileFromJar(...). O mesmo tipo de operação é feito para o carregamento de regras do SOAR.
Em seguida, uma instancia da classe SimulationTask é criada e configurada com os parametros relativos às regras do SOAR e do soarDebbuger. O loop principal da aplicação então é atingido, onde a cada 100 ms o método runSimulation() da instancia da classe SimulationTask é executado até que algum criterio de parada seja atingido.
Esta classe faz uso do WS3DProxy assim como fizemos na Atividade 4 da Aula 1. O WS3DProxy é instanciado no construtor da classe SimulationTask, e quando o método initializeCreatureAndSOAR(...) é chamado, uma criatura é criada no WorldServer3D e tem seu motor inicializado, sendo a instancia da criatura guardada no membro "c". Referências para o proxy e o mundo também são guardadas. Em outros métodos estas referências são utilizadas para submeter comandos para o WorldServer3D e para a criatura. Além dessas referências, outra classes que compõe o pacote WS3DProxy são utilizadas, como a classe CommandUtility. Lembrando que o WS3DProxy implementa uma conexão com o WorldServer3D através de sockets, que funcionam como canais de transmissão de dados entre as aplicações e permitem que uma terceira aplicação como o DemoSOAR possa interagir com os dados gerados e enviar comando a partir de decisões tomadas pelas regras no SOAR.
Para completar a comunicação entre os aplicativos, a classe SimulationTask faz uso do SoarBridge, que também é inicializado no método initializeCreatureAndSOAR(...). O SoarBridge é responsável pela comunicação com o SOAR, em analogia ao WS3DProxy com o WorldServer3D.
Para entendermos como funciona a troca de dados entre o WorldServer3D e o SOAR através dos proxys decritos, devemos voltar ao loop principal da classe SimulationSOAR, onde vimos que o método runSimulaton() de SimulationTask é executado a cada 100ms. Analisando o método runSimulation, podemos ver que a cada iteração temos:
O arquivo contém as regras de decisão que quando selecionadas, geram os controles comandam o agente durante a simulação. São definidos os operadores:
São definidas as preferências para os operadores que competem entre si, levando em conta os diversos casos de entidades e impasses. Por exemplo, dá-se preferência ao operador see*entity ante os operadores de move*food e move*jewel. Em casos de impasse entre dois operadores iguais de movimento, como o move*jewel vs move*jewel, dá-se preferencia ao que tem a entidade mais próxima. Por fim, o operador de menor preferência é o WANDER.
A partir dos operadores descritos, a operação lógica durante a simulação se dá da seguinte forma:
Para esta atividade foi necessário alterar o código fonte do DEMOSoar e do soar-rules.soar. O código fonte completo dos projetos pode ser encontrado aqui.
As principais alterações estão nas classes:
SimulationRobot.java - Nesta classe foi adicionada a referência para a lista de LeaLefts da criatura. Assim, toda vez que o SimulationRobot é creado, a lista de lealefts é referenciada a partir da Creature original.
SimulationTask.java - Nesta classe, o método runSimulation() foi alterado para atualizar a "Bag" que contem todas as informações sobre os elementos coletados pela criatura. Com esta atualização é possivel então atualizar as informações de itens coletados de cada um dos Leaflets da criatura. Este trabalho é feito entre a atualização de estado e a preparação da criatura para o próximo ciclo de simulação.
SoarBridge.java - Nesta classe a alteração foi no método setupStackHolder(..) que passou então a incluir um elemento no working memory do soar, chamado LEAFLET para os elementos do tipo JEWEL e que estão ainda faltantes naquele momento em algum dos leaflets daquela criatura.
soar-rules.soar - Por fim, o arquivo de regras foi alterado para levar em conta o elemento leaflet na memória e uma regra de preferencia foi adiconada para dar preferencia a movimentos em direção a joias que estejam marcadas com LEAFLET 1 quando comparados com joias marcadas com LEAFLET 0 (ou seja não estão em nenhum dos leaflets daquela criatura).
Para testar o funcionamento, basta executar os programas, e para ajudar na visualização do objetivo, foi adicionado um critério de parada (em SimulationTask) quando todas as joias desejadas são coletadas. Uma exceção genéria é lançada apenas para interromper o simulador, além disso, pode-se acompanhar também os logs no console do java.
Os arquivos do java webstart podem ser acessados por aqui:
Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer