Atividade 2
Objetivo
O objetivo da simulação no WorldServer é capturar os cristais e ganhar pontos. A criatura deve capturar os critais que estão especificados no seu leaftlet (Figura 1) e fazer a entrega no Delivery Spot. Ou seja, a criatura deve colocar em sua sacola apenas os cristais da cor e quantidade especificada, dirigir-se ao ponto de entrega e fazer a entrega.
Figura 1 - Leaflet da criatura no WorldServer3D
Modificações no DemoSOAR
Foi necessário modificar o DemoSOAR para que ele pudesse trazer o leaflet do WorldServer e evia-lo ao SOAR de uma forma que fosse possível a execução das regras.
Para fazer a leitura do leaflet, foi utilizado o WS3DProxy alterando o método prepareAndSetupCreatureToSimulation() da classe SimulationTask
simulationCreature.setLeafletList(creature.getLeaflets());
Para montar a estrutura do leaflet e envia-lo ao SOAR foi utilizada a classe SoarBridge, alterando o método setupStackHolder():
if (!creatureParameter.getLeafletList().isEmpty() && creatureLeaflet == null){
creatureLeaflet = agent.CreateIdWME(creature, "LEAFLET");
Map<String, Integer> colors = new HashMap<String, Integer>();
for(Leaflet leaflet: creatureParameter.getLeafletList()){
HashMap collect = leaflet.getWhatToCollect();
Iterator it = collect.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
if (colors.get((String)pair.getKey()) == null){
colors.put((String)pair.getKey(), (Integer)pair.getValue());
}else{
colors.put((String)pair.getKey(), colors.get((String)pair.getKey()) + (Integer)pair.getValue());
}
}
}
Iterator it2 = colors.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry pair = (Map.Entry)it2.next();
System.out.println(pair.getKey() + ":"+ pair.getValue());
Identifier entity = agent.CreateIdWME(creatureLeaflet, "ITEM");
agent.CreateStringWME(entity, "COLOR", (String)pair.getKey());
agent.CreateIntWME(entity, "QTY", (Integer)pair.getValue());
}
}
Para que a criatura pudesse ralizar a entrega do leaflet, é necessário incluir o tratamento para o comando DELIVER.
No método processResponseCommands da classe SimulationTask, foi incluido um novo token de retorno, para que quando o SOAR retornar este comando, o mesmo possa ser enviado ao WorldServer:
case DELIVER:
processDeliverCommand((SoarCommandDeliver)command.getCommandArgument());
break;
O comando DELIVER e o Id do leaflet a ser entregue, será passado para o WorldServer através do WS3DProxy.
private void processDeliverCommand(SoarCommandDeliver soarCommandDeliver) throws CommandExecException
{
if (soarCommandDeliver != null)
{
c.deliverLeaflet(soarCommandDeliver.getLeafletId());
}
else
{
throw new NullPointerException("soarCommand is null");
}
}
Também é necessário modificar o SoarBridge para montar o parâmetro do comando DELIVER:
case DELIVER:
String leafletId = null;
command = new SoarCommand(SoarCommand.CommandType.DELIVER);
SoarCommandDeliver commandDeliver = (SoarCommandDeliver)command.getCommandArgument();
if (commandDeliver != null)
{
leafletId = pCommand.GetParameterValue("LeafletID");
if (leafletId != null)
{
commandDeliver.setLeafletId(leafletId);
}
commandList.add(command);
}
break;
Também é necessário modificar as regras (soar-rules.soar) para que ele leve em consideração as cores e quantidades dos cristais especificados no leaftlet da criatura ao decidir qual cristal capturar.
Regra para propor mover-se pela primeira vez a um cristal que esteja no leaflet, ou seja, quando o atributo GOT não existir para um item do leaflet.
sp {propose*move*jewel*firsttime
(state <s> ^io.input-link <il>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^ENTITY <entityInMemory>)
(<creature> ^POSITION <creaturePosition>)
(<creaturePosition> ^X <creaturePositionX>)
(<creaturePosition> ^Y <creaturePositionY>)
(<entityInMemory> ^TYPE JEWEL)
(<entityInMemory> ^X <entityInMemoryPositionX>)
(<entityInMemory> ^Y <entityInMemoryPositionY>)
(<entityInMemory> ^NAME <entityInMemoryName>)
(<entityInMemory> ^COLOR <entityInMemoryColor>)
(<creature> ^LEAFLET <leaflet>)
(<leaflet> ^ITEM <item>)
(<item> ^COLOR <colorItem>)
(<item> ^QTY <jewelQty> > 0)
-(<item> ^GOT <gotQty>)
(<entityInMemory> ^COLOR <colorItem>)
-->
(<s> ^operator <o> +)
(<o> ^name moveJewel)
(<o> ^parameter <jewel>)
(<jewel> ^distance (sqrt (+ (* (- <creaturePositionX> <entityInMemoryPositionX>) (- <creaturePositionX> <entityInMemoryPositionX>)) (* (- <creaturePositionY> <entityInMemoryPositionY>) (- <creaturePositionY> <entityInMemoryPositionY>)))))
(<jewel> ^X <entityInMemoryPositionX>)
(<jewel> ^Y <entityInMemoryPositionY>)
(<jewel> ^NAME <entityInMemoryName>)
(<jewel> ^COLOR <entityInMemoryColor>)}
Regra para propor mover-se a um cristal que esteja no leaflet e o número de elementos capturados (GOT) daquela cor não ultrapassar a quantidade especificada no leaflet (QTY).
sp {propose*move*jewel
(state <s> ^io.input-link <il>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^ENTITY <entityInMemory>)
(<creature> ^POSITION <creaturePosition>)
(<creaturePosition> ^X <creaturePositionX>)
(<creaturePosition> ^Y <creaturePositionY>)
(<entityInMemory> ^TYPE JEWEL)
(<entityInMemory> ^X <entityInMemoryPositionX>)
(<entityInMemory> ^Y <entityInMemoryPositionY>)
(<entityInMemory> ^NAME <entityInMemoryName>)
(<entityInMemory> ^COLOR <entityInMemoryColor>)
(<creature> ^LEAFLET <leaflet>)
(<leaflet> ^ITEM <item>)
(<item> ^COLOR <colorItem>)
(<item> ^QTY <jewelQty>)
(<item> ^GOT <gotQty> < <jewelQty>)
(<entityInMemory> ^COLOR <colorItem>)
-->
(<s> ^operator <o> +)
(<o> ^name moveJewel)
(<o> ^parameter <jewel>)
(<jewel> ^distance (sqrt (+ (* (- <creaturePositionX> <entityInMemoryPositionX>) (- <creaturePositionX> <entityInMemoryPositionX>)) (* (- <creaturePositionY> <entityInMemoryPositionY>) (- <creaturePositionY> <entityInMemoryPositionY>)))))
(<jewel> ^X <entityInMemoryPositionX>)
(<jewel> ^Y <entityInMemoryPositionY>)
(<jewel> ^NAME <entityInMemoryName>)
(<jewel> ^COLOR <entityInMemoryColor>)}
Regra para capturar um cristal que esteja no leaflet e ainda nao tenha sido capturado nenhum daquela cor, ou seja, o atributo GOT nao existe.
sp {apply*get*jewel*firsttime
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<io> ^output-link <ol>)
(<o> ^name getJewel)
(<o> ^parameter.NAME <jewelName>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^COUNT <quantity>)
(<memory> ^ENTITY <memoryEntity>)
(<memoryEntity> ^NAME <memoryEntityName> <jewelName>)
(<creature> ^LEAFLET <leaflet>)
(<leaflet> ^ITEM <item>)
(<item> ^COLOR <colorItem>)
-(<item> ^GOT <gotQty>)
(<memoryEntity> ^COLOR <colorItem>)
-->
(<ol> ^GET <command>)
(<command> ^Name <jewelName>)
(<memory> ^COUNT <quantity> -
^COUNT (- <quantity> 1))
(<memory> ^ENTITY <memoryEntity> -)
(<item> ^GOT 1)}
-> Inicializa o atributo GOT
Regra para capturar o cristal que esteja no leaflet e o número de elementos capturados (GOT) daquela cor não ultrapassar a quantidade especificada no leaflet (QTY).
sp {apply*get*jewel
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<io> ^output-link <ol>)
(<o> ^name getJewel)
(<o> ^parameter.NAME <jewelName>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^COUNT <quantity>)
(<memory> ^ENTITY <memoryEntity>)
(<memoryEntity> ^NAME <memoryEntityName> <jewelName>)
(<creature> ^LEAFLET <leaflet>)
(<leaflet> ^ITEM <item>)
(<item> ^COLOR <colorItem>)
(<item> ^GOT <gotQty>)
(<memoryEntity> ^COLOR <colorItem>)
-->
(<ol> ^GET <command>)
(<command> ^Name <jewelName>)
(<memory> ^COUNT <quantity> -
^COUNT (- <quantity> 1))
(<memory> ^ENTITY <memoryEntity> -)
(<item> ^GOT <gotQty> -
(+ <gotQty> 1))
-> Incrementa o atributo GOT
}
Para evitar que a criatura fique bloqueada por um cristal indesejado, a regra abaixo permite a captura de cristais que estao no leaflet, apenas se estiverem proximas:
sp {apply*get*jewel*noleaflet
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<io> ^output-link <ol>)
(<o> ^name getJewel)
(<o> ^parameter.NAME <jewelName>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^COUNT <quantity>)
(<memory> ^ENTITY <memoryEntity>)
(<memoryEntity> ^NAME <memoryEntityName> <jewelName>)
(<creature> ^LEAFLET <leaflet>)
(<leaflet> ^ITEM <item>)
-(<item> ^COLOR <colorItem>)
(<memoryEntity> ^COLOR <colorItem>)
* Estas regras ainda não permitem que o SOAR decida quando e onde entregar o leaflet. Ainda não foi possível:
Identificar qual leaflet ja está completo;
Neste estado, dirigir a criatura até o ponto de entrega;
Efetivamente realizar a entrega.
Código fonte
Download do codigo fonte do DemoSOAR modificado e o projeto para NetNeans.
As alterações feitas estão comentadas com a palavra "IA006"
DemoSOAR.tar.gz
Webstart para o DemoSOAR
WorldServer3D WebStart
DemoSOAR WebStart
Simulação
Na Figura 2 é possível ver a execução do DemoSOAR modificado, onde apenas os cristais contidos no leaflet são capturados. Perceba também que a quantidade de cada cristal é respeitado. Na imagem, o cristal da cor verde não foi capturado pois não está no leaflet.
Figura 2 - Finalização da simulação com a captura apenas dos cristais especificados no leaflet
Ao finalizar a captura de todos os cristais desejados, a criatura ficara no operador WANDER, pois não há mais o que ser feito.
No SoarDebugger, a estrutura dos leaflets (Figura 3) é representado como um elemento ITEM e os atributos COLOR, GOT e QTY. Onde COLOR é a cor do cristal no leaflet, QTY é a quantidade desejada e GOT é a quantidade já capturada.
Figura 3 - Estrutura do Leaflet no Input do Soar, visto através do SoarDebugger
OBS: Pode ocorrer uma captura indesejada de um cristal que não está no leaflet, caso este cristal esteja no caminho da criatura. Este comportamento é útil pois evita que a criatura fique bloqueada e continue seu percurso.
Utilização de 2 criaturas competindo em um mesmo ambiente
Não foi possivel realizar esta atividade. O DemoSoar finaliza de forma inexperada ao ser executado mais de uma vez tentando conectar-se a um mesmo WorldServer. Será ainda necessário investigar as causas.