Nessa atividade foi implementada uma solução para a criatura realizar a busca por jóias ( Thing.CATEGORY_JEWEL ).
Adicionamente, foi gerado um comportamento apetitivo na criatura para que também buscasse por comida, perecível ( Thing.categoryPFOOD ) ou não ( Thing.CATEGORY_NPFOOD ). Uma vez que o ítem, quer seja jóia ou comida, é detectado pelo sensor visual da critura, ela passa a buscar o ítem, como pode ser observado no vídeo abaixo.
Podemos observar que, mesmo o ítem sendo movimentado para outras posições no World Server 3D, a criatura continua a perseguí-lo.
As "coisas" buscadas já estavam declaradas na classe Thing, permitindo o reuso do código destacado abaixo:
public class Thing { ( ... ) public const int categoryPFOOD = 21; public const int CATEGORY_NPFOOD = 22; public const int CATEGORY_JEWEL = 3; ( ... ) }
Para a implementação do novo comportamento, dois novos tipos de ações foram enumerados na classe ClarionAgent, a saber, GOTO_ITEM e GET_ITEM.
public enum ClarionAgentActionType { DO_NOTHING, ROTATE_CLOCKWISE, GO_AHEAD, GOTO_ITEM, GET_ITEM }
Ainda na classe ClarionAgent, duas novas constantes foram criadas, representando um ítem no campo visual ( DIMENSION_ITEM_AHEAD ) ou um ítem passível de ser guardado na mochila ( DIMENSION_SACK_ITEM ). Dois novos pares dimensão-valor foram criados como entrada da percepção visual e serão alimentados com as constantes DIMENSION_ITEM_AHEAD e DIMENSION_SACK_ITEM no construtor do ClarionAgent.
public class ClarionAgent { #region Constants ( ... ) private const String DIMENSION_ITEM_AHEAD = "ItemAhead"; private const String DIMENSION_SACK_ITEM = "SackItem"; ( ... ) #region Perception Input ( ... ) private DimensionValuePair dvpInputItemAhead; private DimensionValuePair dvpInputSackItem; ( ... ) }
Abaixo, o trecho do código retirado do construtor:
public ClarionAgent( ) { // Initialize the agent CurrentAgent = World.NewAgent( "Current Agent" ); // Initialize input information InputWallAhead = World.NewDimensionValuePair( SENSOR_VISUAL_DIMENSION, DIMENSION_WALL_AHEAD ); // Initialize output actions OutputRotateClockwise = World.NewExternalActionChunk( ClarionAgentActionType.ROTATE_CLOCKWISE.ToString( ) ); OutputGoAhead = World.NewExternalActionChunk( ClarionAgentActionType.GO_AHEAD.ToString( ) ); dvpInputItemAhead = World.NewDimensionValuePair( SENSOR_VISUAL_DIMENSION, DIMENSION_ITEM_AHEAD ); dvpInputSackItem = World.NewDimensionValuePair( SENSOR_VISUAL_DIMENSION, DIMENSION_SACK_ITEM ); ( ... ) //Create thread to simulation runThread = new Thread( RunThread ); Console.WriteLine( "Agent started" ); }
Agora precisamos definir as ações externas que o agente irá realizar (neste caso, ir para o ítem e pegar o ítem) quando apresentado aos respectivos inputs. O método NewExternalActionChunk realiza isso:
eacOutputGotoItem = World.NewExternalActionChunk( ClarionAgentActionType.GOTO_ITEM.ToString( ) ); eacOutputGetItem = World.NewExternalActionChunk( ClarionAgentActionType.GET_ITEM.ToString( ) );
O próximo passo é instruir o avatar com as regras que serão usadas na seleção da ação. Para isso, criamos os seguintes métodos:
private double fixedRuleDelegateGoToItemAhead( ActivationCollection activationCollection, Rule rule ) { return activationCollection.Contains( dvpInputItemAhead, CurrentAgent.Parameters.MAX_ACTIVATION ) ? 1 : 0; } private double fixedRuleDelegateSackItem( ActivationCollection activationCollection, Rule rule ) { return activationCollection.Contains( dvpInputSackItem, CurrentAgent.Parameters.MAX_ACTIVATION ) ? 1 : 0; }
Esses métodos serão assinalados como SupportCalculator e definidos como regras para o agente para serem selecionados no Action-Centered Subsystem:
SupportCalculator goToItem = fixedRuleDelegateGoToItemAhead; FixedRule ruleGoToItem = AgentInitializer.InitializeActionRule( CurrentAgent, FixedRule.Factory, eacOutputGotoItem, goToItem ); CurrentAgent.Commit( ruleGoToItem ); SupportCalculator sackItem = fixedRuleDelegateSackItem; FixedRule ruleSackItem = AgentInitializer.InitializeActionRule( CurrentAgent, FixedRule.Factory, eacOutputGetItem, sackItem ); CurrentAgent.Commit( ruleSackItem );
Como última modificação na classe ClarionAgent, precisamos fazer o agente perceber as novas situações. O método MakePerceptionFromSensorialInput foi alterado com duas novas informações sensoriais. Caso haja um ítem (jóia, comida perecível ou comida não perecível) no campo visual do agente, uma informação sensorial é adicionada. Caso esse ítem esteja a uma distância passível de ser capturado ( ITEM_SACKABLE_DISTANCE ), outra informação sensorial é adicionada ao SensoryInformation, como mostra o trecho abaixo:
private SensoryInformation MakePerceptionFromSensorialInput( IList< Thing > sensorialInformation ) { SensoryInformation si = World.NewSensoryInformation( CurrentAgent ); ( ... ) const int ITEM_SACKABLE_DISTANCE = 20; Boolean bItemAhead = sensorialInformation.Where( item => ( item.CategoryId == Thing.CATEGORY_JEWEL || item.CategoryId == Thing.CATEGORY_NPFOOD || item.CategoryId == Thing.categoryPFOOD ) ).Any( ); double dItemAheadActivationValue = bItemAhead ? CurrentAgent.Parameters.MAX_ACTIVATION : CurrentAgent.Parameters.MIN_ACTIVATION; si.Add( dvpInputItemAhead, dItemAheadActivationValue ); Boolean bSackItem = sensorialInformation.Where( item => ( ( item.CategoryId == Thing.CATEGORY_JEWEL || item.CategoryId == Thing.CATEGORY_NPFOOD || item.CategoryId == Thing.categoryPFOOD ) && item.DistanceToCreature <= ITEM_SACKABLE_DISTANCE ) ).Any( ); double dSackItemActivationValue = bSackItem ? CurrentAgent.Parameters.MAX_ACTIVATION : CurrentAgent.Parameters.MIN_ACTIVATION; si.Add( dvpInputSackItem, dSackItemActivationValue ); ( ... ) return si; }
Finalmente, a classe Main precisa ser alterada para lidar com os tipos de ação ClarionAgentActionType.GOTO_ITEM e ClarionAgentActionType.GET_ITEM. Neste ponto é importante destacar que, se o ítem for uma jóia, ele é armazenado na mochila ( worldServer.SendSackIt( ) ) e, se o ítem for comida, é usado para alimentar a criatura ( worldServer.SendEatIt( ) ). O trecho abaixo demonstra a implementação desse comportamento.
case ClarionAgentActionType.GOTO_ITEM: foreach( Thing t in agent_OnNewVisualSensorialInformation( ) ) { if( t.CategoryId == Thing.CATEGORY_NPFOOD || t.CategoryId == Thing.categoryPFOOD || t.CategoryId == Thing.CATEGORY_JEWEL ) { Console.WriteLine( "I saw an item at [ " + t.comX + " , " + t.comY + " ]..." ); worldServer.SendSetGoTo( creatureId, 1, 1, t.comX, t.comY ); } } break; case ClarionAgentActionType.GET_ITEM: foreach( Thing t in agent_OnNewVisualSensorialInformation( ) ) { if( t.CategoryId == Thing.CATEGORY_JEWEL ) { Console.WriteLine( "It's close. I can take [ " + t.Name + " ]..." ); worldServer.SendSackIt( creatureId, t.Name ); Console.WriteLine( "I took [ " + t.Name + " ]!" ); } else if( t.CategoryId == Thing.CATEGORY_NPFOOD || t.CategoryId == Thing.categoryPFOOD ) { Console.WriteLine ("It's close. I can eat [ " + t.Name + " ]..." ); worldServer.SendEatIt( creatureId, t.Name ); Console.WriteLine( "I ate [ " + t.Name + " ]!" ); } } break;
Neste teste, duas criaturas implementadas em diferentes arquiteturas cognitivas devem co-habitar um mundo virtual. A primeira criatura foi reaproveitada do Relatório 2 - SOAR: Controlando o WorldServer3D e a segunda criatura foi desenvolvida com a arquitetura cognitiva Clarion e pertence a Atividade Teste 1 descrita neste relatório.
As criaturas puderam co-existir, sendo que o comportamento da simulação 1 (SOAR) de gerar ítens randômicos foi preservado, assim como o comportamento da simulação 2 (Clarion) de criar paredes ao redor do mundo; todavia, a criatura desenvolvida com a arquitetura SOAR não se movimentou, ficando o trabalho de recolher os ítens a cargo da criatura criada com a arquitetura Clarion. A captura de tela abaixo ilustra a situação:
Um arquivo com os executáveis do controlador Clarion está disponível aqui e, depois de descompactado, pode ser executado com o comando:
mono ClarionDEMO.exe
Por favor, certifique-se que o World Server 3D esteja rodando primeiro. O binário foi compilado para conectar-se ao mundo virtual em localhost:4011.
O código fonte está disponível aqui para fins de consulta e recompilação do controlador.
Para iniciar uma simulação conjunta com a arquitetura SOAR, faça o download desse arquivo, descompacte-o e execute o shell script. Após a inicialização do World Server, pressione uma tecla para inicializar o Demo SOAR. Após a inicialização do Demo SOAR, pressione novamente para inicializar a simulação Clarion.
Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer