A seguinte imagem apresenta o programa iniciando de Eaters
Ilistração 1
Apos carregar o arquivo move-to-food.soar é rodado o programa e a saída dele e apresentada na Ilustração 2
Nesta parte o eater começo a comer algumas bolinhas até ele chegar no canto inferior esquerdo, ali ele ficou presso e o Soar Debugger apresento a seguinte mensagem:
Goal stack depth exceeded on a no-change impasse. Soar appears to be in an infinite loop.
Ilustração 2
Quando é feita um segundo teste o resultado é o apresentado na Ilustração 3. O eater fica quieto quando não tem comida nos quadros ao redor dele.
Ilustração 3
A saída do SoarDebugger apresentada na Ilustração 4, mostra que quando o eater está numa posição que não tem comida nos quadros do lado ele apresenta a massagem:
==>S: S13 (state no-change)
Essa mensagem significa que não existe nenhuma regra que possa ser utilizada nesse estado, é dizer, quando o eater fica sem comida ao redor dele, ele não sabe o que fazer e o programa entra num loop infinito onde o estado não muda.
Ilustração 4
Na ilustração 5 é apresentado o código em SOAR do arquivo move-to-food.soar. Neste arquivo é definido um operador chamado
Ilustação 5
P1: Como o estado atual da criatura é considerado nas regras ?.
R: Na primeira regra a condição pergunta se a criatura tem alimento em algum quadro perto dele.
P2: Como a decisão de ação escolhida é aplicada de fato ao jogo ?
R: A ação de decisão é proposta como aleatória por meio dos caracteres “+” e “=”.
P3: Como esse conjunto de regras escolhe a direção para a qual a criatura deve se mover ?
R: O conjunto de regras neste arquivo escolhe a direção perguntando somente se ela tem comida ou não. Se ele tem comida então propõe o operador de movimentação, se não tem comida não faz nada.
P4: Para que serve a regra apply*move-to-food*remove-move ?
R: A regra apply*move-to-food-remove-move serve para eliminar o comando de saída quando ele este completo.
P5: O que aconteceria se ela não existisse ?
R: Se a regra apply*move-to-food-remove-move não existisse a criatura se movimentaria só na direção proposta na primeira aplicação da regra já que para cada aplicação da regra vai ter a mesma saía, a primeira delas.
P6: Quais são as limitações desse programa ?
R: As limitações desse programa é o fato de não considerar a opção da criatura quedar sem comida nos quadros adjacentes, porque ela só é verdadeira quando a criatura tem comida em algum quadro perto.
P7: O que seria necessário fazer para que ele não ficasse paralizado, depois de um tempo ?
R: Seria necessária a implementação de um operador que contemple a possibilidade da criatura se movimentar quando não tivesse comida nos quadros adjacentes.
Building a Simple Eater Using Rules
O primeiro que será feito é um operador que permita à criatura se movimentar para o norte.
Todo estado tem um atributo chamado io que a sua vez tem outro atributo chamado output-link.
Em Soar, todas as ações externas são realizadas por elementos na working memory que são agregados ao elemento output-link
Em Eaters o comado de movimentação (move) é emitido criando o agregado no objeto output-link. O elemento move também tem um atributo chamado direction com o valor da direção a se movimentar.
Os valores validos para direction são: “north”, “south”, “east”, ou “west”. A estrutura do comando de saída é apresentada na Ilustração 6.
Ilustração 6
Por cada tarefa em Soar, é definido um conjunto de comandos, e neste casso tem-se duas tarefas: movimentar (move) e pular (jump)
Move-north operator
O primeiro operador a ser realizado é o move-north operator o operador simplesmente vai gerar um comando de movimentação na direção norte. A proposta da regra em inglês é:
# Propose*move-north:
# If I exist, then propose the move-north operator.
# Apply*move-north:
# If the move-north operator is selected, then generate an output command to
# move north.
A Proposta em soar ele é:
sp {propose*move-north
(state <s> ^type state)
-->
(<s> ^operator <o> +)
(<o> ^name move-north)}
E a aplicação é:
sp {apply*move-north
(state <s> ^operator <o>
^io <io>)
(<io> ^output-link <out>)
(<o> ^name move-north)
-->
(<out> ^move <move>)
(<move> ^direction north)}
A saída no Soar é apresentada na Ilustração 7. Aqui se pode ver como o operador move-north é aplicado e depois o estado não muda mais. Neste ponto a criatura só se pode movimentar uma umica vez para o norte.
Ilustração 7
A saída do jogo é apresentada na Ilustração 8
Ilustração 8
Para lograr que a criatura se movimente mais de uma vez é necessário criar uma instancia do operador e aplicá-lo cada vez que se tenha uma mudança no estado. Para obter essa mudança se pode utilizar a entrada do estado. Ao movimentar a criatura ela cambia de posição, e sua entrada também cambia, então o ciclo ficaria assim:
Ilustração 9
A estrutura do objeto de entrada para o programa eater é apresentada na Ilustração 10.
Ilustração 10
É modificada a proposta do operador para que ele fique assim:
sp {propose*move-north
(state <s> ^io.input-link.eater <e>)
(<e> ^x <x> ^y <y>)
-->
(<s> ^operator <o> +)
(<o> ^name move-north)}
A ilustração 11 apresentada a saída do programa com a codificação na regra.
Ilustração 11
Agora serão escritas as regras para que a criatura se movimente a qualquer espaço perto dele que tenha comida, as regras em inglês são:
# Propose*move-to-food*normalfood
# If there is normalfood in an adjacent cell,
# propose move-to-food in the direction of that cell
# and indicate that this operator can be selected randomly.
# Propose*move-to-food*bonusfood
# If there is bonusfood in an adjacent cell,
# propose move-to-food in the direction of that cell
# and indicate that this operator can be selected randomly.
# Apply*move-to-food
# If the move-to-food operator for a direction is selected,
# generate an output command to move in that direction.
# Apply*move-to-food*remove-move:
# If the move-to-food operator is selected,
# and there is a completed move command on the output link,
# then remove that command.
A Ilustração 12 apresenta a saída do jogo e do SoarDebugger
Ilustração 12
Debugging Soar Programs
Os programas de Soar podem ter dois tipos de erros, os erros de sintaxe e os erros semânticos. Os erros de sintaxe são facilmente detectáveis usando a ferramente VisualSoar. Os error semânticos são erros da lógica do programa e são as vesses mais difíceis de achar, para isso o Soar tem muitos comandos para ajudar na localização de esse tipo de erros
Generalized Move Operator
A regra de proposta do operador para o movimento da criatura, em inglês é:
# Propose*move:
# If there is no wall
# propose move in the direction of that cell
# and indicate that this operator can be selected randomly.
A Ilustração 13 apresenta o final do jogo. A criatura consegui acabar toda a comida, mas demora muito, 2238 movimentos.
Ilustração 13
Para melhorar esse tempo se podem propor regras de preferência, para que Soar pegue um operador mas adequado.
A primeira dessas regras que é a criatura prefira ir onde esta a comida com bonus, do que a comida normal ou que o espaço vazio ou onde esta outra criatura.
# Select*move*bonusfood-better-than-normalfood
# If there is a proposed operator to move to a cell with bonusfood and
# there is a second proposed operator to move to a cell that is empty or
# has normalfood or another eater
# prefer the first operator.
Para colocar um operador em melhor posição do que outro é possível utilizar a preferência de melhor (better) utilizando o símbolo “>”. O caso contrário também é valido, quando se quer colocar um operador em uma posição inferior se usa o operador de (worse) utilizando o símbolo “<”
Assim a regra para propor o operador que coma comida com bonus sobre as demais possibilidades é:
A regra para que a criatura prefira ir para um espaço vazio ou com outra criatura pode ser colocada como menor adequada usando o operador de (worse)
A Ilustração 14 apresenta o jogo completado, com as novas regras de preferência o número de movimentos diminuiu até 764.
Ilustração 14
Advanced Move Operator Proposal
Nesta seção são criadas as regras necessária para que o a criatura não faça o movimento anterior ao feito, evitanto assim que perca energia indo por exemplo de esquerda a direita e de nodo de direita a esquerda. Para evitar esse tipo de comportamento é necessária a criação de estruturas que sejam permanentes e não sejam eliminadas após aplicar o operador.
Na Ilustração 15 é possível ver que a última direção tomada foi o norte, assim nas regras propostas não esta contemplada a possibilidade dê-se movimentar para o sul.
Ilustração 15
Na Ilustração 16 pode-se ver como o jogo termina com menos passos (477) do que na etapa anterior da Ilustração 14 (764)
Ilustração 16