You are here

Atividade 3 - Criação de um algorítmo para busca dos recarregadores

Criação de um algoritmo para levar o agente até os recarregadores de ENERGIA e SAÚDE.
 

Veja o código fonte final aqui.

 

 

3.1. Abordagem adotada

3.2. Novos operadores de alto nível

3.3. Principais extensões utilizadas

3.4. Algoritmo de busca do caminho

3.5. Algoritmo para percorrer o caminho encontrado

3.6. Principais problemas/desafios enfrentados

3.7. Status Final e possibilidades futuras

 


 

3.1. Abordagem adotada

 
Foi escolhida a abordagem de "back-tracking" para encontrar um caminho - não necessariamente o mais curto - até o recarregador desejado. Para essa implementação, escolheu-se utilizar o mecanismo de subestados do Soar para implementar a recursão do "back-tracking".
 
Durante os passos do "back-tracking", quando existem mais de uma direção possível para ser seguida, o algorítmo utiliza a distância de Manhattan para tentar escolher a melhor opção.
 
 

3.2. Novos operadores de alto nível

 
Para a implementação das buscas dos recarregadores de ENERGIA e SAÚDE foram criados os seguintes operadores de alto nível:
 
  • ENERGY: operador que é proposto toda vez que o nível de energia fica abaixo de um limite e o tanque já detectou em algum momento onde está o recarregador de energia; além disso, existe também a verificação de não ter encontrado ainda um caminho - inexistência da extensão "^path-complete", para evitar o impasse com o operador FOLLOW-PATH. Abaixo está a sua regra de proposição:
#
# Propose recharge energy activity
#
 
sp {propose*recharge-energy-activity
   (state <s> ^name tanksoar
              ^io.input-link <il>
             -^path-complete *yes*
              ^map.square.energy)
   (<il> ^energy <= 800)
-->
   (<s> ^operator <o> +)
   (<o> ^name energy)
   (write (crlf) | Proposing recharge energy activity |)
}
 

 

Esse operador será mais prioritário que o operador de alto nível WANDER e também do HEALTH (descrito a seguir); ou seja, o tanque deverá buscar o recarregador de energia preferencialmente a ficar vagando pelo tabuleiro ou ir buscar o recarregador de saúde.

 
  • HEALTH: operador que é proposto toda vez que o nível de saúde fica abaixo de um limite e o tanque já detectou, em algum momento, a posição do recarregador de saúde. Além disso, existe também a verificação de não ter encontrado ainda um caminho - inexistência da extensão "^path-complete", para evitar o impasse com o operador FOLLOW-PATH. Abaixo está a sua regra de proposição:
#
# Propose recharge health activity
#
 
sp {propose*recharge-health-activity
   (state <s> ^name tanksoar
              ^io.input-link <il>
             -^path-complete *yes*
              ^map.square.health)
   (<il> ^health <= 700)
-->
   (<s> ^operator <o> +)
   (<o> ^name health)
   (write (crlf) | Proposing recharge health activity |)
}
 
 
Esse operador deve ser mais prioritário que o operador WANDER.
 
 
  • FIND-RECHARGER: operador de alto nível utilizado apenas a partir dos subestados ENERGY e HEALTH e também recursivamente - a partir do subestado FIND-RECHARGER - durante a busca do recarregador. Abaixo estão as regras de proposição desse operador:
#
# Propose to find a path to the energy recharger through a high-level operator
#
 
sp {energy*propose*find-energy-recharger-path
   (state <s> ^name energy
              ^recharger-state
             -^path-complete
              ^top-state <ts>)
   (<ts> ^square <sq>
         ^recharger-searched <rs>)
-->
   (<s> ^operator <o> +
        ^next-position <sq>
        ^next-move none)
   (<o> ^name find-recharger)
   (write (crlf) | Proposing find | <rs> | recharger activity. |)
}
 
 
 
#
# Propose to find a path to the health recharger through a high-level operator
#
 
sp {health*propose*find-health-recharger-path
   (state <s> ^name health
              ^recharger-state
             -^path-complete
              ^top-state <ts>)
   (<ts> ^square <sq>
         ^recharger-searched <rs>)
-->
   (<s> ^operator <o> +
        ^next-position <sq>
        ^next-move none)
   (<o> ^name find-recharger)
   (write (crlf) | Proposing find | <rs> | recharger activity. |)
}
 
 
 
sp {find-recharger*propose*find-recharger
   (state <s> ^name find-recharger
              ^position <cp>
              ^next-move <direction>
              ^next-position <next-square>)
   (<cp> ^x <x>
         ^y <y>)
   (<next-square> ^x <nx>
                  ^y <ny>)
-->
   (<s> ^operator.name find-recharger +)
   (write (crlf) | FIND RECHARGER: Proposing find rechargere from (| <x> |, | <y> |) to (| <nx> |, | <ny> |)|)
}
 
 
As duas primeiras regras são bastante similares, uma vez que o operador FIND-RECHARGER funciona igualmente para qualquer um dos recarregadores (energia ou saúde) consultando a extensão "^recharger-state" - criada o estado principal, a qual armazena o nome do recarregador procurado.
 
Já o terceiro operador representa a recursão executada durante o algoritmo de back-tracking do próprio subestado FIND-RECHARGER, toda vez que múltiplos caminhos são possíveis a partir de uma posição.
 
 
  • FOLLOW-PATH: operador de alto nível, proposto a partir do estado inicial toda vez que o caminho para algum dos recarregadores tiver sido encontrado, o que é indicado pela extensão "^path-complete" criada no estado principal. Abaixo está a sua regra de proposição:

 

#
# Propose follow path found to recharger
#
 
sp {propose*follow-path-activity
   (state <s> ^name tanksoar
              ^path-complete *yes*
              ^map.square.<rs>
              ^top-state <ts>)
   (<ts> ^recharger-searched <rs>)
-->
   (<s> ^operator <o> +)
   (<o> ^name follow-path)
   (write (crlf) | Proposing follow | <rs> | recharger path activity |)
}
 

Esse operador será mais prioritário que o WANDER.

 

3.3. Principais extensões utilizadas

 
As seguintes extensões foram criadas no estado principal para suportar o mecanismo de busca dos recarregadores:
 
  • "^recharger-searched": pode assumir os valores "energy" ou "health" para indicar qual recarregador está sendo buscado. O seu valor é definido durante a etapa de inicialização dos subestados ENERGY e HEALTH.
  • "^path-complete": é criado com o valor "*yes*" quando foi encontrado um caminho até o recarregador indicado em "^recharger-searched".
  • "^path": armazena a lista de posições que compõem o caminho até o recarregador sendo buscado; pode ter seu valor alterado durante o processo de busca, executado no subestado FIND-RECHARGER; ao final da busca - quando "^path-complete *yes*" - contém o caminho até o recarregador, que será utilizado pelo operador de alto nível FOLLOW-PATH. Cada posição armazenada tem a seguinte estrutura:
^path.position <pos>
<pos> ^step <current-step>
      ^square <current-square>
 
A primeira posição armazenada no caminho é a posição atual do tanque, armazenada como "^step 1".
  • "^step-go": armazena o passo atual dentro do caminho até o recarregador; utilzado pelo subestado FOLLOW-PATH, indicando qual o próximo passo que deve ser executado dentro do caminho armazenado em "^path".

 

As próximas extensões são criadas dentro do subestado ENERGY ou HEALTH como suporte para o operador de alto nível FIND-RECHARGER:
 
  • "^current-step": Passo corrente do caminho até o recarregador; inicializado com ZERO nos subestados ENERGY e HEALTH e usado como base para a inicialização do subestado FIND-RECHARGER.
  • "^visited": lista de posições já visitadas durante todo o processo de busca; manipulado pelo subestado FIND-RECHARGER para guiar o processo de busca do caminho, evitando que o algoritmo insista em posições já percorridas. Armazena as posições com extensões iguais a do "^path".
  • "^recharger-state": inicialmente aponta para o próprio estado - ENERGY ou HEALTH - e passado para as instâncias do subestado FIND-RECHARGER de forma a permitir o acesso essencialmente à extensão "^visited".
  • "^next-position": preenchido quando a próxima posição do caminho é determinada; utilizada na inicialização do subestado FIND-RECHARGER e preechida com a posição atual nos subestados ENERGY e HEALTH.
  • "^next-move": preenchido quando a direção absoluta ("north", "south", "west" e "east") do próximo movimento é definida; também utilizada na inicialização do subestado FIND-RECHARGER e preenchida com o valor "none" nos subestados ENERGY e HEALTH.
  • "^substate": preechido com o subestado criado para a operação de alto nível FIND-RECHARGER. Seu uso principal é durante a recursão dos subestados FIND-RECHARGER; nos subestados ENERGY e HEALTH é criado apenas porque a mesma elaboração dispara na primeira instância do FIND-RECHARGER.
 
 
  • "^position": Armazena a posição atual na busca do caminho até o recarregador; inicializado com o valor de "^next-position" do superestado de uma instância de FIND-RECHARGER - o qual pode ser um subestado ENERGY, HEALTH ou outra instãncia de FIND-RECHARGER.
  • "^last-move": Armazena a direção da último movimento no caminho até o recarregador; inicializado com o valor de "^next-move" do superestado de uma instância de FIND-RECHARGER - o qual pode ser um subestado ENERGY, HEALTH ou outra instãncia de FIND-RECHARGER.
  • "^current-step": Armazena o passo atual no caminho até o recarregador; inicializado com o valor de "^current-step" do superestado de uma instância de FIND-RECHARGER - o qual pode ser um subestado ENERGY, HEALTH ou outra instãncia de FIND-RECHARGER.
  • "^available": Extensões que indicam quais direções podem ser percorridas pelo processo de busca do caminho até o recarregador procurado. Essas direções não devem levar a posições bloqueadas no mapa nem a posições já visitadas - consulta na extensão "^visited" do subestado ENERGY ou HEALTH. Cada extensão possui o seguinte formato:

^available.{<< north south west east >> <direction>} <square>

A elaboração que cria essas extensões foi afetada pelos problemas das regras de atualização do mapa descritos na atividade 2, uma vez que a regra esperava que apenas um tipo de objeto fosse descrito para uma determinada posição, tal como o sensor radar devolve:

 

sp {find-energy*elaborate*available-directions
   (state <s> ^name find-recharger
              ^position <cp>
              ^recharger-state <es>)
   (<cp> ^<direction> <side-square>
         ^x <cx>
         ^y <cy>)
   (<side-square> ^<< energy health open missiles >> *yes*
                  ^x <sx>
                  ^y <sy>)
  -{(<es> ^visited.position <pos>)
    (<pos> ^square <side-square>)}
-->
   (<s> ^available.<direction> <side-square>)
   (write (crlf) | FIND RECHARGER: From (| <cx> |, | <cy> |) can go | <direction> | to (| <sx> |, | <sy> |)|)
}
 
  • "^recharger-state": Indica o subestado original do processo de busca de recarregador: ENERGY ou HEALTH. Inicializado com o valor de "^recharger-state" do superestado de uma instância de FIND-RECHARGER  - o qual pode ser um subestado ENERGY, HEALTH ou outra instância de FIND-RECHARGER.
  • "^substate": indica se o estado atual tem um subestado; necessário para evitar que operadores disparem em instâncias de FIND-RECHARGER que ficaram para-trás no procedimento recursivo de busca do caminho. Ver o algoritmo descrito a seguir.
  • "^remove-substate": Indica que o subestado do estado atual deve ser removido; utilizado durante o processo de backtracking do algoritmo de busca, para remover a partir do seu superestado uma instância de FIND-RECHARGER que não conseguiu chegar até o recarregador procurado.

 

3.4. Algoritmo de busca do caminho

 
A algoritmo de busca do caminho é implementado, de fato, no subestado FIND-RECHARGE, o qual é chamado recursivamente sempre que múltiplas direções são possíveis numa determinada posição. A sua sequência de execução é descrita a seguir.
 

Inicialização

 
Primeiramente, a instância do FIND-RECHARGER é inicializada, criando suas extensões de trabalho a partir do seu superestado.
 
 

Armazenamento da posição atual

 
Uma vez inicializado, são propostos os seguintes operadores dentro do subestado FIND-RECHARGER:
 
  • "save-current": para armazenar a posição corrente na busca do caminho até o recarregador; é o operador mais prioritário.
  • "backtrack-move": retornar um passo na busca do caminho, proposto quando não existe direções disponíveis para percorrer.
  • "single-move": para mover para a única direção disponível a partir da posição atual.
  • "multi-move": para tentar recursivamente uma das direções disponíveis a partir da posição atual.

Conforme comentado, o operador mais prioritário é o "save-current"; assim, ele é executado logo após a inicialização; a regra de aplicação desse operador é a seguinte:

 
sp {find-recharger*apply*save-current
   (state <s> ^name find-recharger
              ^operator.name save-current
              ^position <cp>
              ^last-move <lm>
              ^top-state <ts>
              ^recharger-state <es>
              ^current-step <cur-step>)
   (<ts> ^path <path>)
   (<es> ^visited <visited>)
   (<cp> ^x <x>
         ^y <y>)
-->
   (<path> ^position <pos>)
   (<pos> ^step (+ <cur-step> 1)
          ^abs-direction <lm>
          ^square <cp>)
   (<visited> ^position <pv>)
   (<pv> ^step (+ <cur-step> 1)
         ^square <cp>)
   (<s> ^current-step (+ <cur-step> 1)
        ^current-step <cur-step> -)
   (write (crlf) | FIND RECHARGER: Save current position (| <x> |, | <y> |) in path |)
}
 

Somente quando a posição atual é armazenada é que a extensão "^current-step" é atualizada.

Somente após sua execução que as extensões indicando as direções disponíveis para percorrer tornam-se válidas, uma vez que elas dependem da lista de posições visitadas.

 

Passos na única direção disponível

 
Depois que a posição atual é armazenada, caso exista apenas uma posição disponível o busca seguirá para ela, com a aplicação do operador "single-move"
 
sp {find-recharger*apply*single-movement
   (state <s> ^name find-recharger
              ^operator <o>
              ^position <cp>
              ^last-move <lm>)
   (<o> ^name single-move
        ^<direction> <next-square>)
   (<next-square> ^x <x>
                  ^y <y>)
-->
   (<s> ^position <next-square>
        ^last-move <direction>
        ^position <cp> -
        ^last-move <lm> -)
   (write (crlf) |>> FIND RECHARGER: Applying Move single | <direction> | to (| <x> |, | <y> |)|)
}
 
Como esse operador altera a extensão "^position",  após sua aplicação o operador "save-current" é novamente proposto e aplicado, uma vez que sua regra de proposição leva a "^position" em consideração:
 
sp {find-recharger*propose*save-current
   (state <s> ^name find-recharger
              ^position <cp>
              ^top-state <ts>
              ^last-move <lm>
             -^substate
              ^current-step <cur-step>)
  -{(<ts> ^path.position <pos>)
    (<pos> ^step <cur-step>
           ^square <cp>)}
   (<cp> ^x <x>
         ^y <y>)
-->
   (<s> ^operator <o> +)
   (<o> ^name save-current)
   (write (crlf) | FIND RECHARGER: Propose save current position (| <x> |, | <y> |)|)
}
 
Dessa forma, enquanto houver apenas uma direção disponível para percorrer, o algoritmo a seguirá, armazenando as posições percorridas tanto na lista que compõe o caminho ("^path") quanto na que indica as posições já visitadas ("^visited").
 
 

Recursão no caso de múltiplas direções disponíveis

 
Caso a partir da posição atual existam várias direções disponíveis, o algoritmo criará uma nova instância do subestado FIND-RECHARGER para percorrer, uma por vez, cada uma delas. Isso é feito através do operador "multi-move".
 
A recursão é feita em duas etapas: primeiramente são criadas as extensões "^next-move" e "^next-position" que serão a base para a próxima instãncia do FIND-RECHARGER, indicando qual é a direção disponível que foi escolhida para ser explorada. Depois que essas extensões estão criadas, é então proposto novamente o operador de alto nível FIND-RECHARGER. Ambas regras estão a seguir:
 
sp {find-recharger*apply*multi-movement   
   (state <s> ^name find-recharger
              ^operator <o>
              ^position <cp>
              ^last-move <lm>)
   (<o> ^name multi-move
        ^<direction> <next-square>
        ^distance <distance>)
   (<cp> ^x <x>
         ^y <y>)
   (<next-square> ^x <nx>
                  ^y <ny>)
-->
   (<s> ^next-move <direction>
        ^next-position <next-square>)
   (write (crlf) |>> FIND RECHARGER: Applying multi move | 
                       <direction> | from (| <x> |, | <y> |) to (| <nx> |, | <ny> |), distance | <distance> |.|)
 
 
 
sp {find-recharger*propose*find-recharger
   (state <s> ^name find-recharger
              ^position <cp>
              ^next-move <direction>
              ^next-position <next-square>)
   (<cp> ^x <x>
         ^y <y>)
   (<next-square> ^x <nx>
                  ^y <ny>)
-->
   (<s> ^operator.name find-recharger +)
   (write (crlf) | FIND RECHARGER: Proposing find rechargere from (| <x> |, | <y> |) to (| <nx> |, | <ny> |)|)
}
 
Essa nova instância de FIND-RECHARGER irá então explorar a direção possível, seguindo este mesmo algoritmo.
 
Uma vez que o algoritmo implementado acha o primeiro caminho possível até o recarregador procurado - e não o melhor (mais curto) caminho - é neste ponto de propor qual das direções disponíveis seguir é que ocorre a avaliação de qual delas está à menor distância do recarregador; esse cálculo é feito utilizando-se a distância de Manhattan simples:]
 
#
# Prefer apparently shortest path - Manhantan distance - among multi-moves
#
 
sp {find-recharger*select*shortest-multi-move
   (state <s> ^name find-recharger
              ^operator <op1> +
              ^operator <op2> +
              ^top-state.map.square.energy <e-sq>)
   (<op1> ^name multi-move
          ^<dir1> <n-sq-1>
          ^distance <dist1> < <dist2>)
   (<n-sq-1> ^x <x1>
             ^y <y1>)
   (<op2> ^name multi-move
          ^<dir2> <n-sq-2>
          ^distance <dist2>)
   (<n-sq-2> ^x <x2>
             ^y <y2>)
-->
   (<s> ^operator <op1> > <op2>)
   (write (crlf) | FIND RECHARGER: Select multi-move to (| <x1> |, | <y1> |) distance | <dist1> | over (|
                                                        <x2> |, | <y2> |) distance | <dist2> |.|)
}
 
Embora não garanta que o melhor caminho seja escolhido, essa seleção é capaz de escolher a melhor opção em situações mais simples.
 
 
 

Retornando passos na busca do caminho - backtracking 

 
Caso não existam direções disponíveis a partir da posição atual é proposto o retorno até o primeiro ponto anterior onde haviam múltiplas direções possíveis, correspondendo à etapa de backtracking do algoritmo.
 
A aplicação do operador "backtrack-move" é feita por duas regras: a primeira cria no superestado a extensão "^remove-substate yes", para indicar que esse superestado deve remover essa instância do FIND-RECHARGER.
 
A segunda regra remove do caminho as posições percorridas nessa instância do FIND-RECHARGER que não conseguiram levar até o recarregador procurado; são removidos todos os passos no caminho a partir do passo em que o superestado estava quando essa instância do FIND-RECHARGER foi criada:
 
sp {find-recharger*apply*backtrack*remove-bad-path
   (state <s> ^name find-recharger
              ^operator.name backtrack-move
              ^superstate <ss>
              ^top-state <ts>)
   (<ss> ^current-step <split-step>)
   (<ts> ^path <path>)
   (<path> ^position <pos>)
   (<pos> ^step { <path-step> > <split-step> }
          ^square <sq>)
   (<sq> ^x <x>
         ^y <y>)
-->
   (<path> ^position <pos> -)
   (write (crlf) |>> FIND RECHARGER: Applying backtrack - removing path step | <path-step>  | (| <x> |, | <y> |)|)
}
 
 

Conclusão do caminho até o recarregador procurado

 
A conclusão do caminho até o recarregador procurado é identificada durante o processo de aplicação do operador "save-current"; nesse momento a extensão "^path-complete *yes*" é criada no estado principal, o que acarreta a destruição da instância de ENERGY ou HEALTH e assim de todas as instâncias de FIND-PATH.
 
Nesse momento também é criada a extensão "^step-go 2" no estado inicial, para indicar por qual passo começar a percorrer o caminho armazenado em "^path" quando estiver movendo o tanque para o recarregador.
 
 

Comentários adicionais ao algoritmo

 
A execução do algoritmo de busca do caminho pode ser interrompida caso o tanque esteja ameaçado - com o operador de alto nível RETREAT sendo proposto - ou se o tanque tem a oportunidade de atacar um oponente - com o operador de alto nível ATTACK sendo proposto.
 
Os testes também revelaram que o algoritmo deve ser interrompido caso o tanque ressucite - ou seja, foi morto durante esse processo.
 
 
 

3.5. Algoritmo para percorrer o caminho encontrado

 
Uma vez que o caminho até o recarregador procurado é definido, é proposto então o operador de alto nível FOLLOW-PATH. Sua execução é bastante simples, resumindo-se em mover o tanque nas posições registradas na extensão "^path", a partir dos passos sequenciais, indicados em "^step-go":
 
#
# Propose to follow the calculated path to the energy recharger once has found it
#
 
sp {follow-path*propose*follow-path
   (state <s> ^name follow-path
              ^io.input-link.direction <tank-direction>
              ^top-state <ts>)
   (<ts> ^path.position <ppos>
         ^step-go <cstep>)
   (<ppos> ^square <cp>
           ^step <cstep>
           ^abs-direction <direction>)
   (<cp> ^x <x>
         ^y <y>)
   (<ts> ^direction-map.<tank-direction>.<relative-direction> <direction>)
   
-->
   (<s> ^operator <o> +)
   (<o> ^name move
        ^actions.move.direction <relative-direction>)
   (write (crlf) | FOLLOW PATH: move step | <cstep> | | <relative-direction> | to position (| <x> |, | <y> |)|)
}
 
Uma vez que o tanque chega até o recarregador, ele permance nessa posição até atingir a carga máxima e depois toda informação relativa às atividades de busca de caminho e ida até o recarregador são removidas. Ambos passos estão representados nas regras a seguir:
 
#
# Cleanup once has recharged
#
 
sp {energy*propose*cleanup-recharge
   (state <s> ^name tanksoar
              ^path-complete *yes*
              ^square <sq>
              ^map.square <sq>
              ^io.input-link <il>
              ^recharger-searched <rs>)
   (<sq> ^<rs> *yes*)
   (<il> ^<rs> 1000)
-->
   (<s> ^operator <o> +)
   (<o> ^name cleanup-recharge)
   (write (crlf) | | <rs> | recharge done. Proposing to cleanup data |)
}
 
 
 
sp {energy*apply*cleanup-recharge
   (state <s> ^operator.name cleanup-recharge
              ^path <p>
              ^step-go <sg>
              ^recharger-searched <rs>)
-->
   (<s> ^path <p> -
        ^path-complete *yes* -
        ^step-go <sg> -
        ^recharger-searched <rs> -)
   (write (crlf) | Cleaning up recharge data. Was recharging | <rs>)
}
 
Assim como durante o processo de busca do caminho, enquanto o tanque está indo até o recarregador esse processo pode ser interrompido por conta de um ataque sofrido ou da possibilidade de atacar o oponente.
 
 
 

3.6. Principais problemas/desafios enfrentados

 
  1. Problemas com o GDS (Goal Dependency Set) que o Soar implementa: essa funcionalidade acrecenta condições adicionais que invalidam um determinado estado. Durante o desenvolvimento do algoritmo de busca, inicialmente foi previso manter uma única extensão para indicar o passo corrente do processo; entretanto, isso teve que ser alterado uma vez que a simples atualização desse passo provocava a destruição da instância corrente do FIND-RECHARGER. Não foi investigado profundamente, mas a indicação dada pelo Soar era que o GDS do estado havia sido alterado e por isso ele havia sido destruído.
  2. Ocorreu um CRASH do Soar quando se tentava remover um atributo de um superestado a partir do seu sub-estado, sendo que essa remoção provocaria a destruição desse subestado. Não foi possível identificar a origem do problema - muito provavelmente desdobramentos nas regras após a remoção; evitou-se o problema mudando a abordagem, destruindo o subestado através de outra maneira e realizando a remoção do atributo a partir do superestado.
 

3.7. Status Final e possibilidades futuras

A implementação entregue possui as seguintes características:

  • O agente é capaz de ir recarregar energia, toda vez que o nível for 800 ou menos; foi escolhido esse valor para facilmente ilustrar a operação.
  • O agente é capaz de ir recarregar energia, toda vez que o nível for 700 ou menos; mais uma vez foi escolhido um valor alto para faciliar a ocorrência dessa operação.
  • Foram feitos testes com 2 agentes em disputa e o funcionamento foi adequado.
  • O algoritmo proposto não é muito eficiente, uma vez que o tanque demora alguns ciclos do jogo - ou seja, algumas vezes 15 ciclos de decisão do Soar - somente para encontrar o caminho. Como por conta da simplificação do algoritmo todo o processo é interrompido - e refeito - se o tanque sofre um ataque (por exemplo) o processo de busca às vezes é executado em vão. Também, para simplificar, não foi implementado o armazenamento do caminho até o recarregador, quando encontrado. Então, mesmo que o tanque consiga encontrar o caminho e chegar até o recarregador, numa próxima necessidade terá que recalculá-lo.
 
Uma otimização que poderia ser feita é a de armazenar os caminhos calculados e, numa próxima necessidade, a busca poderia ser mais rápida, caso a posição atual do tanque esteja dentro de algum dos caminhos já obtidos anteriormente.
 
Uma outra otimização possível seria tentar buscar o caminho mais curto até o recarregador.
 
 
 

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer