You are here

Aula 3 - Soar, Tutorial 2

Atividade 1

A primeira atividade consiste em se familiarizar com a aplicação Eaters e os agentes utilizados para controlar as criaturas do jogo. Conforme as instruções, executamos o programa Eaters e criamos um novo agente, utilizando a produção "move-to-food.soar" para este.

Após selecionar o agente e rodar o programa pela primeira vez, tivemos o seguinte resultado:

O programa possui alguns os indicadores "Food remaining", "Points remaining", "World count", além dá pontuação obtida por cada agente, o que permite avaliar a performance dos agentes utilizados.

Clonando a criatura, é criado um novo agente que utiliza as mesmas regras definidas na produção "move-to-food.soar" que analisaremos a seguir. Neste primeiro momento é possivel notar que a criatura quando envolta apenas por casas vazias interrompe suas ações.

Abrindo a produção no VisualSoar, encontramos o seguinte código na parte de proposição dos operadores:
 

p {propose*move-to-food
   (state <s> ^io.input-link.my-location.<dir>.content 
                 << normalfood bonusfood >>)
-->
   (<s> ^operator <o> + =)
   (<o> ^name move-to-food
        ^direction <dir>)}
 
Para entender melhor esse operador, vamos executar o programa passo-a-passo, observando os estados iniciais na memória de trabalho. Desejamos observar <s> ^io.input-link.my-location.<dir>.content:
 
p S1
(S1 ^epmem E1 ^io I1 ^operator O1 ^operator O3 + ^operator O1 + ^operator O2 +
       ^reward-link R1 ^smem S2 ^superstate nil ^type state)
p I1
(I1 ^input-link I2 ^output-link I3)
 
I1 é o objeto da memória de trabalho que vai manipular a entrada e saída de dados. Nos interessa analisar o input-link:
 
p I2
(I2 ^eater E2 ^my-location M1 ^random 0.6215689182281494)
 
Esse objeto possui um atributo de valor M1, que é um o objeto que descreve a posição inicial do agente:
 
p M1
(M1 ^content eater ^content-name red ^east E3 ^north N1 ^south S3 ^west W1)
 
Os elementos ^east E3 ^north N1 ^south S3 ^west W1 são os valores que serão substituidos pela variável <dir>.  Eles possuem os seguintes atributos ^content:

p E3
(E3 ^content normalfood ^east S6 ^north E4 ^south S8 ^west M1)
p N1
(N1 ^content normalfood ^east E4 ^north N6 ^south M1 ^west N2)
p S3
(S3 ^content normalfood ^east S8 ^north M1 ^south S10 ^west S4)
p W1
(W1 ^content wall ^east M1 ^north N2 ^south S4 ^west W2)
 
Para os 3 primeiros objetos, temos ^content normalfood. Estes satisfazem a comparação a seguir: << normalfood bonusfood >>
Isso nos mostra que esse operador seleciona aleatoriamente uma posiçao adjacente a posição da criatura e verifica se o conteudo dessa é "normalfood"ou "bonusfood". Caso sim, o operador (<o> ^name move-to-food ^direction <dir>) é proposto. A variável <dir> vai conter a direção testada que possui comida.
 
Por ser o único operador proposto, este é o escolhido na fase de decisão:
 
--- decision phase ---
=>WM: (139: S1 ^operator O1)
     1: O: O1 (move-to-food)
p O1
(O1 ^direction south ^name move-to-food)
 
A direção escolhida foi "south". Após isso o operador O1 selecionado passa a fase de aplicação, está esta implementada da seguinte maneira:
 
sp {apply*move-to-food
   (state <s> ^io.output-link <ol>
              ^operator <o>)
   (<o> ^name move-to-food
        ^direction <dir>)
-->
   (<ol> ^move.direction <dir>)}
 
O primeiro teste verifica a existencia do output-link e da existencia do operador criado na fase de proposição. O segundo teste verifica se o operador existente foi criado com os elementos de acordo com estabelecido na fase de proposição, ou seja, ^name move-to-food e ^direction <dir>, onde o valor <dir> ser a direção escolhida.
Satisfeitas, um novo elemento na memória de trabalho é criado em output-link. É a partir desse elemento que a decisão de ação escolhida é de fato aplicada ao jogo.
O disparo da fase de aplicação gera o seguinte resultado:
 
Firing apply*move-to-food
--> 
(M2 ^direction south + :O)
(I3 ^move M2 + :O)
p I3
(I3 ^move M2)
p M2
(M2 ^direction south ^status complete)
 
 
Percebemos que aqui o objeto do output-link (I3) possui agora um elemento ^move M2 que por sua vez possui outro elemento com a direção escolhida ^direction south.
A partir dai o jogo utiliza esse objeto criado na memória de trabalho e executa a movimentação da criatura para baixo. Após essa execução o elemento ^status complete é adicionado a memória de trabalho indicando que essa ação ja foi realizada com sucesso.
 
Essa produção possui ainda outra parte de aplicação de regras, chamada apply*move-to-food*remove-move:
 
sp {apply*move-to-food*remove-move
   (state <s> ^io.output-link <ol>
              ^operator.name move-to-food)
   (<ol> ^move <move>)
   (<move> ^status complete)
-->
   (<ol> ^move <move> -)}
 
Ela executa as mesmas comparações de apply*move-to-food, exceto pelo elemento <move> ^status complete adicionado após a execução do movimento pelo jogo. O resultado é a remoção do elemento ^move <move> do output-link.
Isso é necessário pois esse elemento não é automaticamente removido por ter sido criado pela regra de aplicação de operador acima. Estes elementos de memória não são automaticamente eliminados quando a regra não é mais verdadeira.
 
Executando o programa sem a regra apply*move-to-food*remove-move notamos que a criatura se movimenta apenas uma vez. Isso acontece pois apos a primeira movimentação a memória de trabalho esta "suja" com um elemento <move> ^status <complete>.
 
Conforme observamos durante a execução, a criatura para de se movimentar quando se encontra envolta por casas vazias, mesmo havendo em outras partes do mapa alimento. Isso acontece pois a regra de proposição desse operador só é disparada quando existe alimento imediatamente adjecente (<< normalfood bonusfood>>).
 
Uma solução simples para esse problema seria adicionar a condição "empty" dentro da comparação, tendo agora << normalfood bonusfood empty>>.
 
Atividade 2
 
Uso da interface de entrada e saída de um programa Soar
 
Conforme haviamos visto na aula anterior, na criação de um novo agente, a seguinte estrutura é criada na memória de trabalho:

É através das sub-estruturas I2 e I3 que teremos as interfaces de entrada e saída no programa soar. No caso do programa eaters temos como entrada:

 

p I2
(I2 ^eater E2 ^my-location M1 ^random 0.4009833931922913)
p E2
(E2 ^name blue ^score 5 ^x 9 ^y 15)
p M1
(M1 ^content eater ^content-name blue ^east E3 ^north N1 ^south S3 ^west W1)
 
A representação dessa do objeto input-link é mostrada na figura abaixo.
 

Os objetos E3, N1, S3 e W1 tem subestruturas que definem a visibilidade da criatura, no caso uma matriz de casas 5x5 com a criatura na casa central, proporcionando uma visibilidade de duas casas de distância com os dados de input do programa.

Já a interface de saída é mais simples, tendo como valores apenas a próxima direção de movimento, e se essa ação foi ou não executada:

 

p I3
(I3 ^move M140)
p M140
(M140 ^direction north ^status complete)
 
Uso de shortcuts em programas Soar

Na regra com que trabalhamos no exemplo anterior, notamos a utilização da notação de ".". Ela facilita a escrita e o entendimento do programa quando queremos tratar de um elemento da memória de trabalho com augmentações subsequentes. Sem isso a expressão:
 

   (state <s> ^io.output-link <ol>

Deveria ser reescrita como:

   (state <s> ^io <i>)

   (<i> output-link <ol>)

Uso do SoarJavaDebugger para acompanhar o processo de escolha e aplicação de operadores, por meio de traces.

Na atividade 1 demonstramos como obter as informações da fase de proposição de operadores, tomada de decisão e aplicação de operadores. Também foi possivel através do comando print, analisar a memória de trabalho e observar os objetos de entrada que são utilizados pela tomada de decisão, e os objetos de saída, utilizados para execução do movimento pelo programa.

Diferença entre ações o-supported e i-supported, e WMEs persistentes

As ações o-supported são geradas por regra de aplicação de operador, que criam elementos na memoria de trabalho persistentes. Um exemplo foi o elemento I3 ^move M2 do exemplo da atividade 1, que precisava ser retirado explicitamente pela aplicaçao de uma regra especifica para isso.

Já ações i-supported não criam elementos persistentes na memória de trabalho, sendo estes eliminados assim que a condição da regra passa a não ser verificada. Como exemplo podemos citar as regras de proposição de operadores.

Uso de preferências entre operadores

A utilização de preferência entre operadores

 

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer