Teste 1
Foi criado um programa
para controlar a criatura a partir do programa cliente.
Ações da criatura:
Se encontrar uma
parede na frente então vire à direita;
Se tem algum
objeto diferente de parede, comida ou outra criatura a menos de 35
unidades de distancia, então pegue o objeto;
Se tem comida a
menos de 35 unidades de distância, mas a energia é superior a 450
então vire à direita para desviar da comida;
Se tem alguma
joia na frente então adicione ela em uma lista de joias vistas;
Se tem comida na
frente então adicione ela a uma lista de comidas vistas;
Se a energia
estiver baixa (Fuel < 450) então procure na lista de comida qual
está mais próxima e siga em direção a ela;
Se tem elementos
na lista de joias, então procura a joia que está mais perto e siga
para pegá-la;
Se não encontrar nenhuma joia a frente
então vire à direita.
Cada vez que a criatura
pega um elemento ela verifica sua lista de objetos e compara com a
lista de objetivos (leaflet) se ela tem todas as joias que estão na
leaflet o programa deve acabar e a criatura para.
Foi feito até esse
ponto um programa inicial onde a criatura identifica a joia mais
próxima e vai pegá-la sem verificar sua cor e se ela é um
objetivo, assim possivelmente ela irá obter mais joias do que
realmente precisa. Mas quando o número mínimo de joias for atingido
o programa para e o jogo encerra.
Inicialmente serão
criados: o mundo e a criatura.
Após a criação dos
objetos será chamado o método StartWorld
que gera as paredes externas do mundo, posiciona
aleatoriamente 5 joias de cada tipo (ao todo serão 30 joias) e
posiciona 3 comidas de forma aleatória.
Após essa
inicialização será criado uma leaflet pelo servidor.
Nesta etapa algumas
classes foram adicionadas para organizar os objetivos da criatura:
A classe Goal,
possui 4 atributos (figura 1):
Color: Color da
joia que deve ser procurada
NumRequest:
número de joias que devem ser obtidas da cor dada por Color
NumStack:
número de joias que já foram obtidas pela criatura
completed: Se o
numero de joias solicitadas é igual ao que a criatura já pegou
então o objetivo está completo e completed = True, senão, então
completed = False
Figura 1
A próxima classe (figura2) será a Leaflet,
que
é a lista de objetivos (Gols), essa classe possui 3 atributos:
NumGoals: número de objetivos
na lista
Points: número de pontos que a
criatura irá ganhar se cumprir os objetivos
GoalsList: lista de classes tipo Goal com os objetivos a
serem cumpridos
Figura 2
Após
a criação dessas duas classes foram feitos ajustes em outras
classes existentes:
-
Classe Creature (figura3): foram incluídas duas listas. A primeira é
uma lista de leaflets ou seja, uma lista de objetos tipo Leaflet,
e uma lista de objetos tipo Thing
que contem todas as joias que a criatura já
obteve.
Figura 3
As 4 ações utilizadas pela criatura foram:
private DimensionValuePair InputWallAhead;
private DimensionValuePair InputJewel;
private DimensionValuePair InputFoodAhead;
private DimensionValuePair InputSackIt;
As regras utilizadas foram as seguintes:
Se encontra parede a frente então vire à direita:
// Detecta se tem uma parede a frente
Boolean wallAhead = sensorialInformation.Where(item => (item.CategoryId == Thing.CATEGORY_BRICK && item.DistanceToCreature <= 35)).Any();
if (wallAhead)
{
si.Add(InputSackIt, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputFoodAhead, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputJewel, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION);
return si;
}
Então será
criado um foreach para avaliar cada elemento dentro da
sensorialInformation
List<Thing> JewelList = new List<Thing>();
List<Thing> FoodList = new List<Thing>();
foreach (Thing item in sensorialInformation) {
2. Se encontra um objeto diferente da parede, comida ou
criatura a menos de 35 unidades de distancia, então pega o objeto.
// Detecta se é um objeto a ser obtido
if(item.CategoryId != Thing.CATEGORY_CREATURE && item.CategoryId != Thing.CATEGORY_PFOOD && item.CategoryId != Thing.CATEGORY_NPFOOD && item.CategoryId != Thing.CATEGORY_BRICK && item.DistanceToCreature <= 35)
{
SackItItem = item;
si.Add(InputSackIt, CurrentAgent.Parameters.MAX_ACTIVATION);
si.Add(InputFoodAhead, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputJewel, CurrentAgent.Parameters.MIN_ACTIVATION);
return si;
}
3. Se tem
comida a menos de 35 unidades de distancia, mas a energia é superior
a 450 então vire à direita para desviar da comida.
// Se tiver comida a 35 de distancia e energia maior que 450 desvie
if(item.CategoryId == Thing.CATEGORY_PFOOD && item.DistanceToCreature <= 35 && Oss.Fuel >= 450)
{
si.Add(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION);
si.Add(InputSackIt, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputJewel, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputFoodAhead, CurrentAgent.Parameters.MIN_ACTIVATION);
return si;
}
4. Se tem
uma joia na frente então adicione ela a lista de joias vistas
// Detecta joia e adiciona na lista vista
if(item.CategoryId == Thing.CATEGORY_JEWEL)
JewelList.Add(item);
5. Se tem comida na frende então
adicione ela a uma lista de comidas vistas
// Detecta comida e adiciona na lista vista
if(item.CategoryId == Thing.CATEGORY_PFOOD)
FoodList.Add(item);
6.
Se estiver com baixa energia (Fuel < 450) então procure na lista
de comidas vistas qual a mais próxima e vá pegá-la
if(Oss.Fuel < 450) //se a energia estiver menor que 450
{
if(FoodList.Count > 0)
{
Console.Out.WriteLine("Energia baixa! \n");
FoodList = FoodList.OrderBy(o=>o.DistanceToCreature).ToList();
int x = (int)FoodList[0].X1;
int y = (int)FoodList[0].Y1;
int dis = (int)FoodList[0].DistanceToCreature;
param_food[0] = x;
param_food[1] = y;
param_food[2] = dis;
foodName = FoodList[0].Name;
Console.WriteLine("Comida, Pos: " + x.ToString() + " , " + y.ToString() + " Dist = " + dis.ToString());
si.Add(InputWallAhead, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputSackIt, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputJewel, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputFoodAhead, CurrentAgent.Parameters.MAX_ACTIVATION);
return si;
}
}
7. Caso
possua elementos na lista de joias, então procure a joia mais
próxima e vá pegá-la.
if(JewelList.Count > 0)
{
Console.WriteLine("Found " + JewelList.Count.ToString() + " Jewels !!");
JewelList = JewelList.OrderBy(o=>o.DistanceToCreature).ToList();
int x = (int)JewelList[0].X1;
int y = (int)JewelList[0].Y1;
int dis = (int)JewelList[0].DistanceToCreature;
param[0] = x;
param[1] = y;
param[2] = dis;
si.Add(InputJewel, CurrentAgent.Parameters.MAX_ACTIVATION);
return si;
}
8.
Se não tem joia nenhuma na frente então vire à direita.
si.Add(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION);
si.Add(InputSackIt, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputJewel, CurrentAgent.Parameters.MIN_ACTIVATION);
si.Add(InputFoodAhead, CurrentAgent.Parameters.MIN_ACTIVATION);
return si;
Além das
classes criadas e ajustes foi criado o código abaixo para fazer o
Parse
do leaftlet gerado no servidor.
// faz parser do leaflet!
if(creature.HasLeaflet)
{
int num_leaflet = creature.NumberOfLeaflets;
for(int i = 0; i < num_leaflet ; i++)
{
enumerator.MoveNext();
Leaflet aux = new Leaflet();
SetAttribute(aux, "NumGoals", enumerator);
for(int j = 0; j < Convert.ToInt32(aux.NumGoals); j++)
{
Goal aux2 = new Goal();
SetAttribute(aux2, "Color", enumerator);
SetAttribute(aux2, "NumRequest", enumerator);
SetAttribute(aux2, "NumStack", enumerator);
aux.GoalsList.Add(aux2);
}
SetAttribute(aux, "Points", enumerator);
creature.LeafletList.Add(aux);
}
}
Criatura
no WorldServer3D.
Figura 4
Arquivos
Executável do controlador:
aqui
Código fonte:
aqui
Teste 2
A figura a
seguir mostra as duas criaturas no WorldServer3D.
WorldServer 3D: aqui
Cliente modificado do Soar: aqui
Figura 5