You are here

Aula 4 - Soar, Tutorial 3

Atividade 1

 

O objetivo do jogo TankSoar é controlar através de um programa Soar um tanque em um tabuleiro cercado por muros. O objetivo principal jogo é obter pontos combatendo outros tanques dentro do tabuleiro. Abaixo temos uma demonstração do programa rodando.

 

 

Objetos do jogo

No mapa podemos encontrar os seguintes objetos:

 Obstáculos: Impedem o avanço do tanque nos quadrados ocupados.

Tanque: É a representação da entidade controlada pelo agente Soar.

Míssel: Será utilizado pelo tanque para atacar outros tanques.

Carregador de saúde: É utilizado quando o tanque é danificado e precisa recarregar saúde.

Carregador de energia: É utilizado para quando a energia do tanque descarrega (pela utilização do escudo ou radar). 

 

Na primeira execução, foram criados dois agentes para o jogo, com a produção simple-bot.soar. Cada um deles possui sensores para obter informações sobre o tabuleiro, que são utilizadas para as tomadas de decisão.

O sensores utilizados pelos agentes são de dois tipos:

Sensores Primarios - São sensores que provem informação sobre o mundo exterior.

Blocked Sensor: Detecta se uma posição imediatamente adjacente ao tanque está aberta ou bloqueada.

Incoming Sensor: Detecta se um míssel esta se aproximando do tanque.

Radar Sensor: O radar pode ser ativado se o tanque tiver energia suficiente para isso. Sua visibilidade corresponde a uma coluna de 3 quadrados de largura e distância d correspondente ao ajuste da potência do radar, ou até um objeto bloqueando o radar. Além disso o radar detecta as posicões imediatamente a direita e a esquerda to tanque. A informação retornada sobre os objetos é o tipo do objeto e e onde o mesmo foi visto.

Rwaves Sensor: Detecta se o tanque esta sendo detectado pelo radar de um outro tanque.

Smell Sensor: Detecta o tanque mais próximo, além de dizer quao perto este se encontra e a cor do mesmo. Esse sensor não é bloqueado por obstaculos.

Sound Sensor: Detecta o tanque mais próximo que moveu durante a última decisão, dentro de uma distância de 7 ou menos quadrados. Caso o tanque a ser detectado esteja dentro desse alcance, mas não tenha se movido (e portanto não tenha gerado barulho), a detecção não ira ocorrer. A informação retornada será a direção para o tanque se mover pelo caminho de distância mais curta para chegar no outro tanque.

Sensores secundários - São sensores que provem informações 

Clock: Um contador de tempo, incrementado após cada tomada de decisão.

Direction: A direção para a qual esta voltado o tanque.

Energy: O nível atual de energia do tanque. Caso chegue a zero, não é possível utilizar o radar ou escudo.

Energy Recharger: Indica se o tanque está sobre um carregador de energia.

Health: O nivel atual de saúde do tanque. Caso chegue a zero, o tanque morre e é reiniciado em um quadrado vazio.

Health Recharger: Indica se o tanque está sobre um carregador de saúde.

Missiles: O número de mísseis que o tanque possui.

My-color: A cor do tanque.

Radar-distance: A distância efetiva medida pelo radar na última vez que este foi utilizado.

Radar-status: Indica se o radar está ligado.

Random: Um número real aleatório entre 0 e 1. Muda a cada tomada de decisão.

Ressurected: Indica se o tanque morreu e foi reiniciado.

Shield-status: Indica se o escudo do tanque está ligado.

X e Y: As coordenadas X e Y da localização do tanque no mapa.

 

Na interface gráfica do jogo, podemos selecionar um tanque e ver uma representação gráfica dos sensores Radar, Sound e Smell :

 

Ações do tanque - O tanque possui diversas ações que podem ser executadas, para isso é necessário incluir a ação selecionada na etapa de decisão no output-link.

Move: O tanque pode mover para frente, tras, direita ou esquerda. Um tanque pode mover ou rotacionar, nunca ambos ao mesmo tempo. Caso o tanque tente mover para um quadrado bloqueado ele permanece no mesmo quadrado e perde 100 unidades de saúde. Existe a opção de mover para direção nenhuma, o que indica uma ação de espera.

Rotate: O tanque pode girar para a direita ou para a esquerda.

Fire: O tanque pode disparar um míssel por decisão. Disparar um míssel pode ser feito simultaneamente com qualquer outra ação. O míssel é disparado na direção que o tanque está virado.

Radar: O tanque pode ligar/desligar seu radar. Caso o tanque não tenha energia suficiente, essa ação vai falhar.

Radar Range: O tanque alterar o alcance do seu radar utilizando o comando "radar-power". Esse valor pode ter valores entre 1 e 14.

Shields: O tanque pode ligar/desligar seus escudos e isso pode ser feito simultaneamente com qualquer outra ação. Para ligar o escudo o tanque necessita ter energia sufiente.

 

Atividade 2

 

O primeiro agente proposto é um tanque que simplesmente se move pelo mapa procurando por objetos, similar ao "Eaters" da aula anterior. Desejamos que o tanque mova enquanto encontrar quadrados livres em frente. No caso de encontrar um obstáculo, ele deve girar. Além disso o tanque deve desligar seu radar para conservar energia. 

Para a criação deste agente necessitaremos portanto de 3 operadores, um para mover o tanque, outro para gira-lo e um terceiro para desligar o radar: MOVE, TURN, RADAR-OFF.

Operador MOVE:

1. Caso o quadrado em frente do tanque não esteja bloqueado, propor operador "MOVE"

Escrevendo o código Soar para essa proposição temos:

sp {tanksoar*propose*move

  (state <s> ^name tanksoar
             ^io.input-link.blocked.forward no)
-->
  (<s> ^operator <o> +)
  (<o> ^name move
       ^actions.move.direction forward)}

 

Operador TURN:

1. Se o tanque encontrar um quadrado bloqueado em frente.

1.1. E se a direita OU esquerda não estiverem bloqueados então propor TURN para a direção não bloqueada.

          Crie uma preferencia indiferente para o operador (=) 

          Ligue o radar e ajuste sua potência para 13.

1.2. Caso direita e esquerda estejam bloqueados, propor TURN para a esquerda. (E dessa forma na próxima decisão o tanque vai girar mais uma vez voltando para o sentido oposto

Escrevendo o código para a descrição acima temos:

 

sp {propose*turn
   (state <s> ^name tanksoar
              ^io.input-link.blocked <b>)
   (<b> ^forward yes
        ^ { << left right >> <direction> } no)
-->
   (<s> ^operator <o> + =)
   (<o> ^name turn
        ^actions <a>)
   (<a> ^rotate.direction <direction>
        ^radar.switch on
        ^radar-power.setting 13)}

A outra proposição deve girar o tanque para a esquerda para posteriormente completar o giro de 180 graus e voltar na direção oposta:

 

sp {propose*turn*backward
   (state <s> ^name tanksoar
              ^io.input-link.blocked <b>)
   (<b> ^forward yes ^left yes ^right yes)
-->
   (<s> ^operator <o> +)
   (<o> ^name turn
        ^actions.rotate.direction left)}
 

Operador Radar-off:

1. Se o radar estiver ligado, mas não observando carregadores de energia, saude, mísseis ou tanques, propor operador radar-off.

    Caso radar-off seja proposto, dar preferência a este em relação aos outros operadores.

 

sp {propose*radar-off
   (state <s> ^name tanksoar
              ^io.input-link <il>)
# Verifica que nao há objetos visíveis
   (<il> ^radar-status on
        -^radar.<< energy health missiles tank >>)
-->
   (<s> ^operator <o> +)
   (<o> ^name radar-off
        ^actions.radar.switch off)}
 
sp {select*radar-off*move
   (state <s> ^name tanksoar
              ^operator <o1> +
              ^operator <o2> +)
# Da preferencia ao operador radar-off
   (<o1> ^name radar-off)
   (<o2> ^name << turn move >>)
-->
   (<s> ^operator <o1> > <o2>)}
 

Rodando esse programa com apenas um tanque, podemos observar o comportamento desse operador.

O tanque inicia voltado para um caminho livre em frente, dessa forma as primeiras decisões são operador MOVE:

 

     0: ==>S: S1
     1: O: O1 (move)

 

Após encontrar a parede bloqueando a posição para a qual o tanque está virado, o operador proposto é TURN, além disso o radar é agora ligado:

 

     0: ==>S: S1
     1: O: O1 (move)
     2: O: O2 (move)
     3: O: O4 (turn)


 

Como podems observar pela representação gráfica do radar, não há nenhum objeto de interesse visível a frente, portanto o operador RADAR-OFF é agora proposto:

 

     0: ==>S: S1
     1: O: O1 (move)
     2: O: O2 (move)
     3: O: O4 (turn)
     4: O: O18 (radar-off)
 

 

O tanque então segue em frente até encontrar um novo obstáculo, onde mais uma vez vai propor os operador TURN:

 

     0: ==>S: S1
     1: O: O1 (move)
     2: O: O2 (move)
     3: O: O4 (turn)
     4: O: O18 (radar-off)
     5: O: O17 (move)
     6: O: O19 (move)
     7: O: O20 (move)
     8: O: O21 (turn)
 

 

Subgoals

Para criarmos um agente que realiza o objetivo do jogo, isto é, combater outros tanques, necessitamos criar inteligência para outras ações. Estas assim como no exemplo antérior podem ser atividades de alto nível, como andar pelo mapa, perseguir um outro tanque, atacar ou fugir. Essas ações podem ser decompostas em outros objetivos mais simples, criando assim uma estrutura hierarquica de decisão.

Partindo dos operadores de alto nível Wander, Chase, Attack, Retreat, seguindo a proposta do tutorial, define-se os seguintes sub-goals para cada um deles:

 

Operadores de alto-nível.

Operador Wander

A idéia desse operador é ser selecionado caso não exista a presença de tanques rivais detectada. A descrição pode ser feita da seguinte maneira:

1. Caso não exista tanque visivel no radar.

1.1. E o sensor sound esteja silencioso. 

1.1.1. E não exista nenhum míssel em direção ao tanque.

        Então proponha o operador Wander.

O código Soar fica:

sp {propose*wander

   (state <s> ^name tanksoar
              ^io.input-link <io>)
#Testes negativos para outros tanques, som e misseis vindo na direção do tanque
   (<io> ^sound silent
        -^radar.tank
        -^incoming.<dir> yes)
-->
#Proposição do operador de alto nível Wander
(<s> ^operator <o> +)
(<o> ^name wander)}

 

Operador Chase

O operador chase deve ser selecionado quando o tanque percebe a presença de outro tanque mas não sabe onde exatamente esse tanque está. Para isso devemos utilizar o sensor sound.

1. Se o sensor sound não está silencioso

1.1 E não existir nenhum outro tanque no radar

1.1.1 E se energia ou mísseis não estiverem "low" - Para essa definição devemos utilizar a elaboração de estados.

       Propor operador Chase

Para a elaboração utiliza-se o código soar abaixo:

 

sp {elaborate*state*missiles*low
   (state <s> ^name tanksoar
              ^io.input-link.missiles 0)
-->
#Criação do elemento na memória de trabalho indicando que mísseis ou a energia está baixo
   (<s> ^missiles-energy low)}
 
sp {elaborate*state*energy*low
   (state <s> ^name tanksoar
              ^io.input-link.energy <= 200)
-->
   (<s> ^missiles-energy low)}

 

Para a proposição do operador temos:

 

sp {propose*chase
   (state <s> ^name tanksoar
              ^io.input-link <io>
             -^missiles-energy low)
#Verifica que o algum som foi detectado
   (<io> ^sound <> silent
        -^radar.tank)
-->
   (<s> ^operator <o> +)
   (<o> ^name chase)}

Aplicação do operador Chase

O operador Chase é aplicado através da seleção dos operadores move e turn

 

 

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer