Esta atividade consiste em modificar todo o sistema de integração WorldServer3D e SOAR, para que as criaturas passem a perseguir o seu "leaflet".
1. Análises iniciais
As primeiras dúvidas que surgiram foi a respeito dos leaflets: o que são? Como são definidos? O que exatamente consiste a tarefa requisitada?
Foi estudado o código do WorldServer3D e também feita uma investigação a partir do uso da sua interface via comando telnet. A partir desse estudo, concluiu-se o seguinte:
- Um leaflet é uma lista que indica o tipo (cor) e quantidade de jóias que devem ser coletadas para renderem uma determinada pontuação.
- Cada criatura pode ter uma conjunto de leaflets definidos; na solução desenvolvida, todas as criaturas criadas a partir do proxy já tem uma lista de leaflets definida.
- Para conseguir os pontos definidos por um leaflet a criatura precisa entregar as jóias correspondentes no delivery spot existente no tabuleiro.
O conjunto de leaflets de uma criatura é fornecido pela interface através do comando getcreaturestate, como apresentado a seguir:
getcreaturestate Creature_1367191801082
Creature_1367191801082 0 100.0 100.0 20.0 0.0 2 0.0 0.0 1000 Yellow 1 3 1367191811095 2 White 2 0 Yellow 1 0 6 1367191811093 3 Blue 1 0 Green 1 0 Yellow 1 0 18 1367191811091 2 Blue 2 0 Yellow 1 0 16 0
O formato do comando, como já indicado durante a atividade 1 dessa aula, é o seguinte:
getcreaturestate <nome-criatura>
<nome> <index> <x> <y> <size> <pitch> <motor> <whell-spped> <speed> <fuel> <color> <has-active-leaflet> <leaflet-pool> <visual-sys>
No caso da lista de leaflets, temos a seguinte estrutura:
<leaft-pool>
<number-of-leaflets>
{
{
<leaflet-id>
<number-of-item-types>
<item-color-1>
<item-quantity>
<item-current-count>
.
.
.
<item-color-n>
<item-quantity>
<item-current-count>
<leaflet-score>
}
.
.
.
}
Ainda durante a investigação foram identificadas as seguintes características da implementação atual:
- Na saída do <leaflet-pool>, o campo <item-current-count> não é atualizado corretamente, não sendo possível saber se já foi coletada uma das jóias do leaflet.
- Não existe um comando na interface do WorldServer3D para apresentar o score ou o que uma criatura está carregando; dessa maneira, será necessário manter no lado cliente - ambiente de simulação - a lista das jóias que a criatura for coletando.
- No WorldServer3D apenas a janela "Knapsack and Score" apresenta o que cada criatura está carregando e a sua pontuação, obtida a partir da entrega de leaflets.
- O WorldServer3D não valida o comando "deliver": mesmo que a criatura tente entregar um leaflet que ela não tem completo, ela ganha a pontuação correspondente.
- O comando "deliver" exige que seja indicado o "leaflet ID" como segundo parâmetro, além de receber o nome da criatura; o método CommandUtility.sendDeliverLeaflet implementa apenas o primeiro parâmetro, estando faltando o parâmetro "Leaflet ID"; esse método terá que ser modificado.
2. Sequência de operação para solução do problema
Considerando o problema proposto, a seguinte sequência de operação alto-nível pode ser adotada como abordagem de solução:
- A criatura mantém continuamente o registro de cada jóia que coleta;
- A criatura verifica continuamente se completou algum dos seus leaflets;
- Ao detectar um leaflet completo, a criatura vai até o "delivery spot";
- Ao chegar no "delivery spot" a criatura entrega o leaflet completo;
As etapas acima pressupõe uma série de alterações tanto na parte JAVA quanto nas regras SOAR da solução; essas alterações são descritas a seguir.
3. Alterações parte JAVA
Externalização para o SOAR dos leaflets da criatura
É preciso alterar o código JAVA para que seja passado para o SOAR a lista de leaflets da criatura. Será criada dentro do "input-link" a seguinte estrutura, já abaixo da extensão já existente "^CREATURE":
<creature> ^LEAFLETS <ll>
<ll> ^COUNT HOW-MANY-LEAFLETS-m
<ll> ^LEAFLET <l-1>
<l-1> ^ID LEAFLET-1-ID
<l-1> ^PAYMENT LEAFLET-1-PAYMENT
<l-1> ^<COLOR-1> <ljc-1>
<ljc-1> ^TARGET HOW-MANY-TO-GET-1
^COUNT HOW-MANY-ALREADY-HAVE-1
.
.
.
<l-1> ^<COLOR-n> <ljc-n>
<ljc-n> ^TARGET HOW-MANY-TO-GET-n
^COUNT HOW-MANY-ALREADY-HAVE-n
<ll> ^LEAFLET <l-2>
<l-1> ^ID LEAFLET-2-ID
<l-1> ^PAYMENT LEAFLET-2-PAYMENT
.
.
.
É também preciso altearar o código JAVA para ocorrer a externalização para o SOAR do "delivery spot"; será criada a seguinte estrutura no input-link, também abaixo da extensão "^CREATURE":
<creature> ^DELIVERY-SPOT <ds>
<ds> ^X X-COORD
^Y Y-COORD
Para simplificar as interfaces e também garantir a atualização, ambas extensões - "^LEAFLETS" e "^DELIVERY-SPOT" - serão renovadas a cada ciclo de INPUT do SOAR.
Para realizar as externalizações acima foram feitas as seguintes alterações em arquivos do projeto DemoSOAR:
Alterar classe "SimulationRobot" para receber e externalizar a lista de leaflets, com os novos métodos "setLeafletList()" e "getLeafletList()".
Alterar class "SimulationRobot" para ter também um parâmetro "deliverySpot", também com métodos "setDeliverySpot()" e "getDeliverySpot()".
Alterar método "SimulationTask.prepareAndSetupCreatureToSimulation()" para incluir no objeto "SimulationRobot" a lista de leaflets - obtida a partir do método "Creature.getLeaflets()" - e o deliverySpot - obtido a partir do método "World.getDeliverySpot()".
Alterar método "SoarBridge.setupStackHolder()" para criar no agente o elemento "^LEAFLETS" e toda a sua árvore de informação, conforme descrita anteriormente.
Alterar método "SoarBridge.setupStackHolder()" para criar elemento "^DELIVERY-SPOT", conforme estrutura anteriormente descrita.
Alterar método "SoarBridge.clearEntitiesToNextSimulation()" para apagar elementos "^LEAFLETS" e "^DELIVERY-SPOT" da memória de trabalho, depois que o agente já consultou, garantindo a sua atualização a cada ciclo de INPUT do SOAR.
Comando de entrega dos leaflets
Ainda no código JAVA é preciso realizar as alterações para o uso do comando de entrega dos leaflets, uma vez que a criatura chegar no delivery spot. Como a implementação do
CommandUtility.sendDeliverLeaflet precisará ser alterada, conforme indicado anteriormente, será necessário também alterar o projeto WS3DProxy:
Criar a classe "SoarCommandDeliver" para representar o comando DELIVER, e que deverá ter um atributo "leafletID" e funções "getLeafletID()" e "setLeafletID()".
Alterar classe "SoarCommand" para acrescentar comando DELIVER como um possível parâmetro.
Alterando "SoarBridge.java" para tratar o comando DELIVER no método "SoarBridge.getReceivedCommands()", criando um objeto da classe "SoarCommandDeliver".
Alterar "SimulationTask.java" para tratar comando DELIVER, criando um método "processDeliverCommand()" - onde o método "Creature.deliverLeaflet()" deverá ser chamado - e alterando "processResponseCommands()" para chamar o método anterior no caso do comando DELIVER.
Alterar método "CommandUtility.sendDeliverLeaflet()" para receber parâmetro "leafletID" e compor o comando "deliver" como segundo parâmetro.
public static synchronized StringTokenizer sendDeliverLeaflet(String robotID, String leafletID) throws CommandExecException {
//randomly generates a new leaflet:
String controlMessage = "deliver " + robotID + " " + leafletID;
return sendCmdAndGetResponse(controlMessage);
}
- Alterar método "Creature.deliverLeaflet()" para receber parâmetro "leafletID" e passá-lo para chamada de "CommandUtility.sendDeliverLeaflet()".
O diagrama a seguir apresenta o resultado final, indicando as classes que foram alteradas em vermelho:
4. Alterações nas regras SOAR
Regras para totalização por cor das jóias avistadas
Para facilitar a verificação de quais leaflets estão completos foram criadas regras que realizassem a totalização por cor de todas as jóias avistadas; essa totalização ficará armazenada na seguinte estrutura abaixo da extensão "^MEMORY", que permanece entre os ciclos de execução:
^MEMORY
^jewel-counters
^red NUM-OF-RED-JEWELS
^white NUM-OF-WHIITE-JEWELS
.
.
.
Foram criadas as regras abaixo, variantes de aplicação dos operadores seeEntityWithMemoryCount e seeEntityWithoutMemoryCount:
#
# Jewel colors counters
#
sp {apply*see*entity*with-without*memory*count*update-jewel-counters*new-1
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<io> ^output-link <ol>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<o> ^name << seeEntityWithMemoryCount seeEntityWithoutMemoryCount >>)
(<o> ^parameterEntity <newEntity>)
(<newEntity> ^X <x>)
(<newEntity> ^Y <y>)
(<newEntity> ^Name <name>)
(<newEntity> ^Type JEWEL)
(<newEntity> ^Color <color>)
-(<memory> ^jewels-counters)
-->
(<memory> ^jewels-counters.<color> 1)
(write (crlf) | Creating | <color> | jewels counter. First counter.|)
}
sp {apply*see*entity*with-without*memory*count*update-jewel-counters*new-2
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<io> ^output-link <ol>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<o> ^name << seeEntityWithMemoryCount seeEntityWithoutMemoryCount >>)
(<o> ^parameterEntity <newEntity>)
(<newEntity> ^X <x>)
(<newEntity> ^Y <y>)
(<newEntity> ^Name <name>)
(<newEntity> ^Type JEWEL)
(<newEntity> ^Color <color>)
(<memory> ^jewels-counters <jc>)
-(<jc> ^<color>)
-->
(<jc> ^<color> 1)
(write (crlf) | Creating | <color> | jewels counter. |)
}
sp {apply*see*entity*with-without*memory*count*update-jewel-counters*add
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<io> ^output-link <ol>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<o> ^name << seeEntityWithMemoryCount seeEntityWithoutMemoryCount >>)
(<o> ^parameterEntity <newEntity>)
(<newEntity> ^X <x>)
(<newEntity> ^Y <y>)
(<newEntity> ^Name <name>)
(<newEntity> ^Type JEWEL)
(<newEntity> ^Color <color>)
(<memory> ^jewels-counters <jc>)
(<jc> ^<color> <old-value>)
-->
(<jc> ^<color> <old-value> -
(+ <old-value> 1))
(write (crlf) | Increasing | <color> | jewels counter. Value: | (+ <old-value> 1))
}
Além dessas regras é necessária uma outra para diminuir um contador quando a criatura pegar uma das jóias, uma vez que estão totalizadas as jóias no ambiente; essa regra foi criada como uma variante da aplicação do operador getJewel:
#
# Decrease the environment counter of total jewels of a given color
#
sp {apply*get*jewel*decrease-jewel-counter
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<o> ^name getJewel)
(<o> ^parameter.NAME <jewelName>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^jewels-counters <jc>)
(<jc> ^<jewelColor> <jewel-color-quantity>)
(<memory> ^ENTITY <memoryEntity>)
(<memoryEntity> ^NAME <jewelName>
^COLOR <jewelColor>)
-->
(<jc> ^<jewelColor> <jewel-color-quantity> -
(- <jewel-color-quantity> 1))
(write (crlf) | Decreasing | <jewelColor> | jewels counter. Value: | (- <jewel-color-quantity> 1))
}
Regras para totalização das jóias coletadas - controle do sack da criatura
Para manter o controle de quais jóias foram coletadas e, assim, ser possível verificar quais leaflets estão completos, foi adicionada a seguinte estrutura, também abaixo da extensão "^MEMORY":
^MEMORY
^jewels-sack
^red NUM-OF-RED-JEWELS-IN-SACK
.
.
.
As seguintes regras, também variantes da aplicação do operador getJewel, fazem a atualização dessa estrutura:
#
# Increment the jewels-sack counter for the given color
#
sp {apply*get*jewel*increase-jewels-sack-new-1
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<o> ^name getJewel)
(<o> ^parameter.NAME <jewelName>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
-(<memory> ^jewels-sack)
(<memory> ^ENTITY <memoryEntity>)
(<memoryEntity> ^NAME <jewelName>
^COLOR <jewelColor>)
-->
(<memory> ^jewels-sack.<jewelColor> 1)
(write (crlf) | Put the first | <jewelColor> | jewel in the sack. First of all.|)
}
sp {apply*get*jewel*increase-jewels-sack-new-2
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<o> ^name getJewel)
(<o> ^parameter.NAME <jewelName>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^jewels-sack <js>)
-(<js> ^<jewelColor>)
(<memory> ^ENTITY <memoryEntity>)
(<memoryEntity> ^NAME <jewelName>
^COLOR <jewelColor>)
-->
(<js> ^<jewelColor> 1)
(write (crlf) | Put the first | <jewelColor> | jewel in the sack.|)
}
sp {apply*get*jewel*increase-jewels-sack-new-add
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link <il>)
(<o> ^name getJewel)
(<o> ^parameter.NAME <jewelName>)
(<il> ^CREATURE <creature>)
(<creature> ^MEMORY <memory>)
(<memory> ^jewels-sack <js>)
(<js> ^<jewelColor> <quantity>)
(<memory> ^ENTITY <memoryEntity>)
(<memoryEntity> ^NAME <jewelName>
^COLOR <jewelColor>)
-->
(<js> ^<jewelColor> <quantity> -
(+ <quantity> 1))
(write (crlf) | Put another | <jewelColor> | jewel in the sack. Color total: | (+ <quantity> 1))
}
Operador para ir até o delivery spot quando tiver um leaflet completo
Para criar um operador que comande o agente ir até o delivery spot, no caso de ter um leaflet completo, foi considerada a seguinte
abordagem:
- Verifica se já tem todas as jóias de um determinardo leaflet e não está a menos de 30 de distância do delivery spot (nessa distância pode entregar o leaflet); propõe ir até o delivery spot, passando no operador qual a distância a ser percorrida até lá e qual o pagamento do leaflet (ambas informações serão utilizadas para definir preferência).
- Executa o operador de movimento para leaflet com maior pagamento.
- Se estiver buscando uma jóia (moveJewel) e a distância desse movimento for menor que a do delivery spot vai buscar a jóia. Caso contrário, vai para o delivery spot.
O primeiro trabalho é criar regras que permitam a identificação de um leaflet completo; para permitir que sejam criadas regras genéricas, que avaliem cada cor de jóia de um leaflet, foi criado o operador "updateLeaflets", cujas regras de proposição e aplicação estão a seguir:
#
# Elaborate the current leaflets with the counter of already get jewels
#
sp {propose*update-leaflets-with-jewels-in-sack
(state <s> ^io.input-link.CREATURE.LEAFLETS <lls>)
-(<lls> ^leaflets-done *yes*)
-->
(<s> ^operator <o> +, >)
(<o> ^name updateLeaflets)
(write (crlf) | Proposing to update the leaflets list |)
}
sp {apply*update-leaflets-enough-jewels-in-sack
(state <s> ^operator.name updateLeaflets
^io.input-link.CREATURE <creature>)
(<creature> ^MEMORY.jewels-sack <js>
^LEAFLETS <lls>)
(<lls> ^LEAFLET <ll>)
(<ll> ^{<color> << Blue Green Magenta Yellow Red White >>} <ll-color>)
(<ll-color> ^TARGET <color-target-num>)
(<js> ^<color> <color-count-sack> >= <color-target-num>)
-->
(<ll-color> ^in-sack <color-count-sack>)
(<lls> ^leaflets-done *yes*)
}
sp {apply*update-leaflets-less-jewels-in-sack
(state <s> ^operator.name updateLeaflets
^io.input-link.CREATURE <creature>)
(<creature> ^MEMORY.jewels-sack <js>
^LEAFLETS <lls>)
(<lls> ^LEAFLET <ll>)
(<ll> ^{<color> << Blue Green Magenta Yellow Red White >>} <ll-color>)
(<ll-color> ^TARGET <color-target-num>)
(<js> ^<color> <color-count-sack> < <color-target-num>)
-->
(<ll> ^incomplete *yes*)
(<ll-color> ^in-sack <color-count-sack>)
(<lls> ^leaflets-done *yes*)
}
sp {apply*update-leaflets-no-jewels-in-sack
(state <s> ^operator.name updateLeaflets
^io.input-link.CREATURE <creature>)
(<creature> ^LEAFLETS <lls>)
(<lls> ^LEAFLET <ll>)
(<ll> ^{<color> << Blue Green Magenta Yellow Red White >>} <ll-color>)
-{(<creature> ^MEMORY.jewels-sack <js>)
(<js> ^<color> <color-count-sack> > 0)}
-->
(<ll> ^incomplete *yes*)
(<ll-color> ^in-sack 0)
(<lls> ^leaflets-done *yes*)
}
Essas regras criam uma extensão
"^in-sack" para cada cor de jóia de cada leaflet; essa extensão mantém o número de jóias daquela cor que foram coletadas. Caso esse número seja menor que o número da extensão
"^TARGET" da jóia - extensão que indica quantas jóias devem ser coletadas para aquele leaflet - já é criada uma extensão
"^incomplete *yes*" no elemento do leaflet.
Dessa maneira, a identificação de um leaflet completo para a proposição do operador de ir até o delivery spot fica simplificada:
sp {propose*moveDeliverySpot*complete-leaflet
(state <s> ^io.input-link.CREATURE <creature>)
(<creature> ^DELIVERY-SPOT <ds>
^LEAFLETS <lls>
^POSITION <creaturePosition>)
(<creaturePosition> ^X <c-x>
^Y <c-y>)
(<ds> ^X <ds-x>
^Y <ds-y>
^distance <ds-distance> > 30)
(<lls> ^LEAFLET <ll>
^leaflets-done *yes*)
(<ll> ^PAYMENT <ll-payment>
^ID <ll-id>
-^incomplete *yes*)
-->
(<s> ^operator <o> +)
(<o> ^name moveDeliverySpot
^distance <ds-distance>
^id <ll-id>
^payment <ll-payment>)
(write (crlf) | Proposing go to delivery spot for leaflet | <ll-id> | of payment | <ll-payment> | and distance | <ds-distance>)
}
Ainda para auxiliar o processo foram criadas duas regras para pré-calcular a distância do agente até o delivery spot:
sp {elaborate*deliverySpot*distance
(state <s> ^io.input-link.CREATURE <creature>)
(<creature> ^DELIVERY-SPOT <ds>
^LEAFLETS <lls>
^POSITION <creaturePosition>)
(<creaturePosition> ^X <c-x>
^Y <c-y>)
(<ds> ^X <ds-x>
^Y <ds-y>)
-->
(<ds> ^distance (sqrt (+ (* (- <c-x> <ds-x>) (- <c-x> <ds-x>)) (* (- <c-y> <ds-y>) (- <c-y> <ds-y>)))))
}
sp {monitor*deliverySpot*distance
(state <s> ^io.input-link.CREATURE <creature>)
(<creature> ^DELIVERY-SPOT.distance <ds-distance>)
-->
(write (crlf) | Current distance to delivery spot | <ds-distance>)
}
Por fim, foram criadas regras para determinar a preferência caso vários operadores para ir até o delivery spot sejam propostos, seguindo a
abordagem indicada:
#
# moveDeliverySpot preference rules
#
sp {deliver-higher-payment-leaflet*moveDeliverySpot*preferences
(state <s> ^operator <o1> +
<o2> +)
(<o1> ^name moveDeliverySpot
^id <ll-id-1>
^payment <ll-payment-1>)
(<o2> ^name moveDeliverySpot
^id <ll-id-2> <> <ll-id-1>
^payment <ll-payment-2> <= <ll-payment-1>)
-->
(<s> ^operator <o1> > <o2>)
(write (crlf) | Selecting to go deliver leaflet | <ll-id-1> | (| <ll-payment-1> |) instead of | <ll-id-2> | (| <ll-payment-2> |)|)
}
sp {moveDeliverySpot*moveJewel*preference-1
(state <s> ^operator <o1> +
<o2> +
^io.input-link.CREATURE.DELIVERY-SPOT <ds>)
(<ds> ^distance <distance-ds>)
(<o1> ^name moveDeliverySpot
^id <ll-id-1>
^payment <ll-payment-1>)
(<o2> ^name moveJewel)
(<o2> ^parameter.distance <distance-jewel> >= <distance-ds>)
-->
(<s> ^operator <o1> > <o2>)
(write (crlf) | Selecting to go deliver leaflet | <ll-id-1> | (| <ll-payment-1> |, distance |
<distance-ds> |) instead of moveJewel (distance | <distance-jewel> |)|)
}
sp {moveDeliverySpot*moveJewel*preference-2
(state <s> ^operator <o1> +
<o2> +
^io.input-link.CREATURE.DELIVERY-SPOT <ds>)
(<ds> ^distance <distance-ds>)
(<o1> ^name moveDeliverySpot
^id <ll-id-1>
^payment <ll-payment-1>)
(<o2> ^name moveJewel)
(<o2> ^parameter.distance <distance-jewel> < <distance-ds>)
-->
(<s> ^operator <o1> < <o2>)
(write (crlf) | Selecting to moveJewel (distance | <distance-jewel> |) instead of go deliver leaflet | <ll-id-1> | (|
<ll-payment-1> |, distance | <distance-ds> |) |)
}
Operador para realizar a entrega do leaflet
Uma vez que a criatura estiver no delivery spot é necessário um operador que execute o comando de entrega dos leaflets completos. Para tanto será adotada a seguinte abordagem:
- Verifica se já tem todas as jóias de um determinado leaflet e está a menos de 30 de distância do delivery spot; propõe entregar o leaflet - operador deliverLeaflet - passando no operador o ID do leaflet completo e o valor de pagamento do leaflet
- Executa preferencialmente a entrega de maior valor.
- Este operador deliverLeaflet terá maior preferência que todos os demais.
- Quando realizar a entrega do leaflet precisa diminuir os contadores de jóias em "^jewels-sack".
Seguindo essa abordagem, foram criadas as seguintes regras:
sp {propose*deliverLeaflet
(state <s> ^io.input-link.CREATURE <creature>)
(<creature> ^DELIVERY-SPOT <ds>
^LEAFLETS <lls>
^POSITION <creaturePosition>)
(<creaturePosition> ^X <c-x>
^Y <c-y>)
(<ds> ^X <ds-x>
^Y <ds-y>
^distance <ds-distance> <= 30)
(<lls> ^LEAFLET <ll>
^leaflets-done *yes*)
(<ll> ^PAYMENT <ll-payment>
^ID <ll-id>
-^incomplete *yes*)
-->
(<s> ^operator <o> +, >)
(<o> ^name deliverLeaflet
^id <ll-id>
^payment <ll-payment>)
(write (crlf) | Proposing to deliver leaflet | <ll-id> | of payment | <ll-payment>)
}
sp {apply*deliverLeaflet
(state <s> ^operator <o>
^io <io>)
(<io> ^output-link <ol>)
(<o> ^name deliverLeaflet
^id <ll-id>
^payment <ll-payment>)
-->
(<ol> ^DELIVER <command>)
(<command> ^id <ll-id>)
(write (crlf) | Deliver leaflet | <ll-id> | of payment | <ll-payment>)
}
sp {apply*deliverLeaflet*decrease-jewels-sack
(state <s> ^operator <o>
^io <io>)
(<io> ^input-link.CREATURE <creature>)
(<io> ^output-link <ol>)
(<o> ^name deliverLeaflet
^id <ll-id>)
(<creature> ^LEAFLETS <lls>)
(<lls> ^LEAFLET <ll>)
(<ll> ^ID <ll-id>
^{<color> << Blue Green Magenta Yellow Red White >>} <ll-color>)
(<ll-color> ^TARGET <ll-color-count>
-^already-decreased-from-sack *yes*)
(<creature> ^MEMORY.jewels-sack <js>)
(<js> ^<color> <js-color-count>)
-->
(<js> ^<color> <js-color-count> -
(- <js-color-count> <ll-color-count>))
(<ll-color> ^already-decreased-from-sack *yes*)
(write (crlf) | Leaflet | <ll-id> | delivered. Now has | (- <js-color-count> <ll-color-count>) | | <color> | jewels in sack.|)
}
sp {apply*deliverLeaflet*remove-move
(state <s> ^operator.name deliverLeaflet
^io.output-link <ol>)
(<ol> ^{<cmd> << EAT GET MOVE DELIVER >>} <command>)
(<command> ^status complete)
-->
(<ol> ^<cmd> <command> -)
}
5. Observações gerais
- A regra "apply*moveJewel*remove*jewel" está removendo uma jóia do ambiente quando não deveria, uma vez que não necessariamente a criatura está virada para a jóia quando decide se mover até ela. Essa regra foi removida aparentemente apenas com melhoria do funcionamento.
- Não está claro porque em "propose*see*entity*with*memory*count" ao invés de testar simplesmente a existência da extensão "^COUNT" é testado se ela tem o valor menor que 7. Esse teste foi removido aparentemente sem prejuízo ao funcionamento.
Está faltando uma regra para indicar operadores "getJewel" e "eatFood" com maior preferência do que "seeEntityWithMemoryCount" e "seeEntityWithoutMemoryCount"; nessas condições o agente estava entrando em "tie-impasse" e ficava travado. Foi acrescentada a seguinte regra:
sp {eatFood*getJewel*preferences*over*seeEntity
(state <s> ^operator <o1> +
<o2> +)
(<o1> ^name << getJewel eatFood >>)
(<o2> ^name << seeEntityWithMemoryCount seeEntityWithoutMemoryCount >>)
-->
(<s> ^operator <o1> > <o2>)
}
- De dentro do SOAR não consegue remover uma extensão que veio do INPUT-LINK; por esse motivo não pode ser utilizada a extensão "^COUNT" - criada dentro de cada cor dos leaflets a partir do JAVA - para indicar o total de jóias já coletadas. Por conta disso foi criada a extensão "^in-sack" como indicado anteriormente.
- Os atributos do SOAR são sensíveis à caixa alta/baixa.
- As regras de remoção de comandos já executados não funcionavam quando o próximo comando executado não era igual ao anterior, já que checavam o nome do operador:
sp {apply*wander*remove*move
(state <s> ^operator.name wander
^io.output-link <out>)
(<out> ^MOVE <move>)
(<move> ^status complete)
-->
(<out> ^MOVE <move> -)}
Para evitar que os comandos se acumulassem no OUTPUT-LINK essas regras foram modificadas da seguinte forma:
sp {apply*moveFood*remove-move
(state <s> ^operator.name moveFood
^io.output-link <out>)
(<out> ^{<cmd> << EAT GET MOVE DELIVER >>} <move>)
(<move> ^status complete)
-->
(<out> ^<cmd> <move> -)}
As regras também poderiam ter sido modificadas para que, com apenas uma, todos os comandos já executados fossem removidos.