ENUNCIAT

Realitzar un equip de futbol de robots utilitzant el JavaSoccer. La tècnica d’intel·ligència artificial utilitzada són els agents. Cada jugador serà una agent amb la seva base de coneixement i un conjunt de regles, amb aquestes regles haurà de prendre una decisió de quina és l’acció més convenient a realitzar. Com que el futbol és un joc d’equip els jugadors hauran de consultar la seva decisió amb els companys, la tècnica utilitzada seran els consensos. Les necessitats de cada jugador i el seu prestigi dependrà de com evolucioni el partit.

DESCRIPCIÓ GENERAL

Un Agent-Jugador consta de 4 parts completament diferenciades:

La part d’inicialitzacions s’encarrega de inicialitzar totes les variables sobre la posicions absolutes (les posicions dels companys, dels oponents, de la pilota i de les porteries). També són necessari conèixer la posició relativa de la pilota respecte al nostre agent per saber si la tenim a prop o lluny. També s’han d’inicialitzat tota una sèrie de variables utilitzades per prendre decisions, per realitzar la comunicació amb els companys, per realitzar consensos, …

Per prendre decisions cada jugador té definit un conjunt de regles. Aquestes regles està realitzades amb lògica difusa (Fuzzy). Aquestes regles representen les possibles accions que pot prendre un jugador. La regla amb un valor d’activació més elevat serà la decisió presa pel jugador.

Quan cada jugador ha decidit quina és l’acció a realitzar segons la seva base de coneixement i de les seves regles llavors s’ha de comunicar amb els companys. Cada jugador envia per un canal de comunicació la seva decisió i llegeix les decisions preses pels companys. Si existeix algun conflicte entre la decisió presa per dos agents s’aplica la tècnica de consensos per veure quin dels dos agents té més possibilitats de dur a terme una determinada acció, possiblement un dels dos agents haurà canviar de decisió. La necessitat de cada jugador i el prestigi que poden tenir els companys d’un jugador dependrà de l’evolució del partit.

Un cop els jugadors han consensuat la seva decisió amb els companys el jugador ha de realitzar l’acció corresponent a la decisió presa.
 

INICIALITZACIONS

Existeixen dos tipus de inicialitzacions, les que s’han de realitzar quan s’instancia la classe del jugador i les que s’han de realitzar a cada pas d’execució. Les primeres són variables que no varien en el transcurs del partit o que només s’han d’inicialitzar la primera vegada, s’han de col·locar en un mètode anomenat Configure(), les segones s’han d’executar cada vegada que s’ha de realitzar un pas d’execució i les col·locarem al mètode iniVars().

El mètode Configure() mètode és executat pel JavaBotSim quan comença l’execució del partit. S’ha d’inicialitzar:

Codi del mètode Configure()


/* Metode que configura la classe */
public void Configure()
{
    int i;
    Vec2 temp,jo;

    RobotID = abstract_robot.getPlayerNumber(temps_act);
    // Identificador del robot
    jo = abstract_robot.getPosition(temps_act); // Posicio del robot
    temp = abstract_robot.getOurGoal(temps_act); // Vector jo-porta pròpia
    portaprop = new Vec2( temp.x, temp.y );
    portaprop.add(jo); // Posició porta pròpia
    temp = abstract_robot.getOpponentsGoal(temps_act); // Vector jo-porta contrària
    portacont = new Vec2( temp.x, temp.y );
    portacont.add(jo); // Posició de la porta contrària
    if (portaprop.x<0) // Si som de l'equip de l'Oest
    {
        if (RobotID==2) RobotID=4;
       // Canviem els ids per a tenir els robots ben posicionats
        else if (RobotID==4) RobotID=2;
    }
    // Definició de les segones decisions: si no poden fer una acció
    // el robot farà la segona_decisió
    switch (RobotID)
    {
        case 0:
            Segona_decisio=COBRIR;
            // Porter: anar a cobrir la porteria
            break;
        case 1:
            Segona_decisio=ZONA_DEFENSA;
            // Defensa:zona de defensa a l'alçada de la pilota
            break;
        case 2:
            Segona_decisio=OBERT_DRETA;
            // Mig dret: Zona lateral dreta
            break;
        case 4:
            Segona_decisio=OBERT_ESQUERRA;
            // Mig esquerra: Zona lateral esquerra
            break;
        case 3:
            Segona_decisio=ZONA_ATAC;
            // Davanter: Zona d'Atac
            break;
    }
    messagesin = abstract_robot.getReceiveChannel();// messagein: missatges rebuts
    for (i=0;i<JUGADORS;i++)consensos[i]=0.5; // Valor inicial de necessitat i prestigis
}



El mètode iniVars() s’encarrega d’inicialitzar les variables que van canviant de valor en el transcurs del partit o que s’han d’inicialitzar abans de prendre una decisió. Aquest mètode es cridat al principi del TakeStep() i inicialitza les següents variables:   Codi del mètode iniVars()


void iniVars()
{
    int i;

    temps_act = abstract_robot.getTime();
   for (i=0;i<MAX_DEC;i++) decisions[i]=0;
    jo = abstract_robot.getPosition(temps_act); // Posició del jugador
    jo_pilota = abstract_robot.getBall(temps_act); // Vector jo-pilota
    pilota = new Vec2( jo_pilota.x, jo_pilota.y ); // Posició de la pilota
    pilota.add( jo );
    jo_portaprop = abstract_robot.getOurGoal(temps_act); // Vector jo-porta pròpia
}



PRESA DE DECISIONS

Un cop tenim totes les variables inicialitzades l’agent, en funció de les dades disponibles ha de prendre una decisió utilitzant regles amb lògica difusa. El conjunt de regles utilitzades per cada agent és diferent en funció de la seva funcionalitat, és a dir, si el jugador ha d’actuar com a porter tindrà una regles completament diferents que el jugador que ha d’actuar com a atacant. Al final, de totes les regles aplicades s’ha de decidir quina és l’acció a prendre agafant la que tingui un valor d’activació més alt.

Possibles accions a realitzar per un jugador

Les regles han de permetre decidir quina és l’acció a realitzar, per tant, cal definir quines són les accions realitzables per un jugador. Les accions possibles són les següents:

Tipus de jugadors

Les regles aplicades per cada jugador són diferents en funció de la seva funcionalitat. Hi ha un perfil de jugador per a cada agent:

Conjunts fuzzy

Per poder utilitzar regles amb lògica difusa cal tenir un conjunt de variables fuzzy, a continuació descriurem els conjunts fuzzy que s’han utilitzat. Tots aquest mètodes estan a la classe Fuzzy.


Figura 1. Zones del camp amb un xut clar
Si l’equip que fa la consulta és l’equip de l’est el conjunt fuzzy és el següent:
Si l’equip és el de l’oest llavors el conjunt fuzzy és:
Si l’equip que fa la consulta és l’equip de l’est el conjunt fuzzy és el següent:
Si l’equip és el de l’oest llavors el conjunt fuzzy és:
Si l’equip que fa la consulta és l’equip de l’est el conjunt fuzzy és el següent:
Si l’equip és el de l’oest llavors el conjunt fuzzy és:


Regles de decisió

Les regles utilitzaren lògica difusa, cal implementar els operadors and i or. L’operador lògic and és el producte i l’operador or és la suma menys el producte de dos valors.

Mètode que implementa la or lògica està a la classe Utils.


public static double Or(double d1, double d2)
{
    return d1+d2-(d1*d2);
}

Com que tenim 5 perfils de jugador llavors s’han de definir 5 conjunts de regles.



switch (RobotID)
{
    case 0:/* Regles de decisió del Porter */
        break;
    case 1:/* Regles de decisió del Defensa */
        break;
    case 2:/* Regles de decisió del Mig dret */
        break;
    case 4: /* Regles de decisió del Mig esquerra */
        break;
    case 3: /* Regles de decisió del Davanter */
        break;
}


El valor de cada decisió es guarda a una taula anomenada decisions[] que servirà per escollir l’acció a realitzar per a cada jugador. R1: TenirPilora and XutClar Þ Xutar
R2: JoCampContrari or JoMigCamp or (JoCampPropi and JoObertDreta) or (JoCampPropi and JoObertEsquerra) Þ Cobrir
R3: JoZonaPorteria and JoCentrat Þ Defensar
R4: JoDavantPilota Þ AnarPilota

Codi de les regles


decisions[XUTAR]=f.TenirPilota(jo_pilota)*f.XutClar(jo,pilota,portaprop,top_goalpost(),bottom_goalpost());
decisions[COBRIR]=f.CampContrari(jo,portaprop);
decisions[COBRIR]=u.Or(decisions[COBRIR],f.MigCamp(jo));
decisions[COBRIR]=u.Or(decisions[COBRIR],f.CampPropi(jo,portaprop)*f.ObertDreta(jo,portaprop));
decisions[COBRIR]=u.Or(decisions[COBRIR],f.CampPropi(jo,portaprop)*f.ObertEsquerra(jo,portaprop));
decisions[DEFENSAR]=f.ZonaPorteria(jo,portaprop)*f.Centrat(jo);
decisions[ANAR_PILOTA]=f.Davant(jo,pilota,portaprop);

R1: TenirPilora and XutClar Þ Xutar
R2: JoZonaGol or PilotaZonaGol or (JoCampContrari and LlunyPilota) Þ Defensar
R3: (PilotaDavantJo and JoCampPropi and PilotaCampPropi) or (PilotaDavantJo and JoCampPropi and PilotaMigCamp) Þ AnarPilota
R4: JoDavantPilota Þ Recuperar

Codi de les regles



decisions[XUTAR]=f.TenirPilota(jo_pilota)*f.XutClar(jo,pilota,portaprop,top_goalpost(),bottom_goalpost());
decisions[ZONA_DEFENSA]=f.ZonaGol(jo,portaprop);
decisions[ZONA_DEFENSA]=u.Or(decisions[ZONA_DEFENSA],f.ZonaGol(pilota,portaprop));
decisions[ZONA_DEFENSA]=u.Or(decisions[ZONA_DEFENSA],f.CampContrari(jo,portaprop)*f.LlunyPilota(jo_pilota));
decisions[ANAR_PILOTA]=f.Davant(pilota,jo,portaprop)*f.CampPropi(jo,portaprop)*f.CampPropi(pilota,portaprop);
decisions[ANAR_PILOTA]=u.Or(decisions[ANAR_PILOTA],f.Davant(pilota,jo,portaprop)*f.CampPropi(jo,portaprop)*f.MigCamp(pilota));
decisions[RECUPERAR]=f.Davant(jo,pilota,portaprop);

R1: TenirPilora and XutClar Þ Xutar
R2: (PilotaCampContrari and PilotaObertDreta) or (PilotaCampContrari and PilotaCentrat) Þ Atacar
R3: (PilotaObertEsquerra and JoCampContrari) or (PilotaObertEsquerra and JoMigCamp) Þ ObertDreta
R4: PilotaObertEsquerra and JoZonaPorteria and JoObertDreta Þ Aturar
R5: (PilotaCampPropi and JoDavantPilota and PilotaObertDreta) or (PilotaCampPropi and JoDavantPilota and PilotaCentrat) Þ Recuperar
R6: (PilotaCampPropi and PilotaDavantJo and PilotaObertDreta) or (PilotaCampPropi and PilotaDavantJo and PilotaCentrat)Þ Recuperar

Codi de les regles



decisions[XUTAR]=f.TenirPilota(jo_pilota)*f.XutClar(jo,pilota,portaprop,top_goalpost(),bottom_goalpost());
decisions[ATACAR]=f.CampContrari(pilota,portaprop)*f.ObertDreta(pilota,portaprop);
decisions[ATACAR]=u.Or(decisions[ATACAR],f.CampContrari(pilota,portaprop)*f.Centrat(pilota));
decisions[OBERT_DRETA]=f.ObertEsquerra(pilota,portaprop)*f.CampContrari(jo,portaprop);
decisions[OBERT_DRETA]=u.Or(decisions[OBERT_DRETA],f.ObertEsquerra(pilota,portaprop)*f.MigCamp(jo));
decisions[ATURAR]=f.ObertEsquerra(pilota,portaprop)*f.ZonaPorteria(jo,portaprop)*f.ObertDreta(jo,portaprop);
decisions[RECUPERAR]=f.CampPropi(pilota,portaprop)*f.Davant(jo,pilota,portaprop)*f.ObertDreta(pilota,portaprop);
decisions[RECUPERAR]=u.Or(decisions[RECUPERAR],f.CampPropi(pilota,portaprop)*f.Davant(jo,pilota,portaprop)*f.Centrat(pilota));
decisions[ANAR_PILOTA]=f.CampPropi(pilota,portaprop)*f.Davant(pilota,jo,portaprop)*f.ObertDreta(pilota,portaprop);
decisions[ANAR_PILOTA]=u.Or(decisions[ANAR_PILOTA],f.CampPropi(pilota,portaprop)*f.Davant(pilota,jo,portaprop)*f.Centrat(pilota));

R1: TenirPilora and XutClar Þ Xutar
R2: (PilotaCampContrari and PilotaObertEsquerra) or (PilotaCampContrari and PilotaCentrat) Þ Atacar
R3: (PilotaObertDreta and JoCampContrari) or (PilotaObertDreta and JoMigCamp) Þ ObertEsquerra
R4: PilotaObertDreta and JoZonaPorteria and JoObertEsquerra Þ Aturar
R5: (PilotaCampPropi and JoDavantPilota and PilotaObertEsquerra) or (PilotaCampPropi and JoDavantPilota and PilotaCentrat) Þ Recuperar
R6: (PilotaCampPropi and PilotaDavantJo and PilotaObertEsquerra) or (PilotaCampPropi and PilotaDavantJo and PilotaCentrat) Þ Recuperar

Codi de les regles



decisions[XUTAR]=f.TenirPilota(jo_pilota)*f.XutClar(jo,pilota,portaprop,top_goalpost(),bottom_goalpost());
decisions[ATACAR]=f.CampContrari(pilota,portaprop)*f.ObertEsquerra(pilota,portaprop);
decisions[ATACAR]=u.Or(decisions[ATACAR],f.CampContrari(pilota,portaprop)*f.Centrat(pilota));
decisions[OBERT_ESQUERRA]=f.ObertDreta(pilota,portaprop)*f.CampContrari(jo,portaprop);
decisions[OBERT_ESQUERRA]=u.Or(decisions[OBERT_ESQUERRA],f.ObertDreta(pilota,portaprop)*f.MigCamp(jo));
decisions[ATURAR]=f.ObertDreta(pilota,portaprop)*f.ZonaPorteria(jo,portaprop)*f.ObertEsquerra(jo,portaprop);
decisions[RECUPERAR]=f.CampPropi(pilota,portaprop)*f.Davant(jo,pilota,portaprop)*f.ObertEsquerra(pilota,portaprop);
decisions[RECUPERAR]=u.Or(decisions[RECUPERAR],f.CampPropi(pilota,portaprop)*f.Davant(jo,pilota,portaprop)*f.Centrat(pilota));
decisions[ANAR_PILOTA]=f.CampPropi(pilota,portaprop)*f.Davant(pilota,jo,portaprop)*f.ObertEsquerra(pilota,portaprop);
decisions[ANAR_PILOTA]=u.Or(decisions[ANAR_PILOTA],f.CampPropi(pilota,portaprop)*f.Davant(pilota,jo,portaprop)*f.Centrat(pilota));

R1: TenirPilora and XutClar Þ Xutar
R2: JoDavantPilota and PilotaCampContrari Þ Recuperar
R3: (PilotaDavantJo and PilotaMigCamp) or (PilotaDavantJo and PilotaCampContrari)Þ Atacar
R4: PilotaCampPropi Þ ZonaAtac

Codi de les regles



decisions[XUTAR]=f.TenirPilota(jo_pilota)*f.XutClar(jo,pilota,portaprop,top_goalpost(),bottom_goalpost());
decisions[RECUPERAR]=f.Davant(jo,pilota,portaprop)*f.CampContrari(pilota,portaprop);
decisions[ATACAR]=u.Or(f.Davant(pilota,jo,portaprop)*f.MigCamp(pilota),f.Davant(pilota,jo,portaprop)*f.CampContrari(pilota,portaprop));
decisions[ZONA_ATAC]=f.CampPropi(pilota,portaprop);

Decisió de l’acció a realitzar

Quan el jugador a aplicat les regles llavors s’ha de decidir per quina és l’acció més convenient a realitzar, s’ha de trobar el màxim de la taula de decisions. El mètode Decisio() de la classe Utils, donada la taula de decisions retorna la decisió que ha de prendre el jugador.

Codi del mètode Desicio()



public static int Decisio(double vec[])
{
    int i,pos=0;
    double maxim=vec[0];

    for (i=1;i<vec.length;i++)
    {
        if (vec[i] > maxim)
        {
            maxim=vec[i];
            pos=i;
        }
    }
    return pos;
}


COMUNICACIÓ ENTRE AGENTS

Quan el jugadors ja han decidit quina és l’acció a realitzar es passa a la fase de comunicació Cal enviar al decisió als companys. El jugador ha de rebre les diferents decisions que ha pres i si cal consensuar la decisió. Com que els jugadores són adaptatius cal anar modificant la necessitat i els prestigis de tots els jugadors.

Enviar als companys de decisió presa

A la fase d’inicialització s’ha obert un canal de comunicació. Per enviar la decisió cal omplir una objecte de tipus Enumeration, aquest objecte té dos atributs un serveix per posar-hi l’identificador de jugador que envia el missatge i el segon atribut s’hi ha de posar el missatge a enviar. El missatge que ha d’enviar és la decisió que a pres el jugador i la certesa d’aquesta decisió. Quan l’estructura del missatge ja està completada s’envia utilitzant un broadcast el missatge a tots els companys.

Codi per enviar un missatge



/* Comunicació amb els companys */
m.sender=RobotID;
m.val=(new Integer(decidit)).toString();
m.val=m.val.concat(" ");
m.val=m.val.concat((new Double(decisions[u.Decisio(decisions)])).toString());
abstract_robot.broadcast(m); // Enviar missatge a tots el companys

Rebre les decisions dels companys

El jugador rep el missatge de tots els seus companys. Del missatge s’ha d’extreure l’identificador de qui envia el missatge, la decisió que ha pres i la certesa de la decisió presa. Per obtenir aquest valors s’han creat els següents mètodes de la classe Utils:


public static int ID_company(String m)
{
    Integer v=new Integer(m.substring(8,9));
    return v.intValue();
}


public static int decisio_company(String m)
{
    Integer v=new Integer(m.substring(15,17));
    return v.intValue();
}


public static double certesa_company(String m)
{
    Double v=new Double(m.substring(17));
    return v.doubleValue();
}

Utilitzant aquests mètodes i realitzant un recorregut per la cua de missatges que hem rebut anem recollint les dades de les decisions preses pels companys i es van aplicant els consensos.

double certesa_company;
int id_company,decisio_company;

while (messagesin.hasMoreElements()) // Rebre tots els missatges
{
    StringMessage recvd =(StringMessage)messagesin.nextElement(); // rebre missatge
    String missatge=recvd.toString();

    id_company=u.ID_company(missatge); // id del company que ha enviat el missatge
    decisio_company=u.decisio_company(missatge); // decisió del company
    certesa_company=u.certesa_company(missatge); // certesa de la decisió del company

    // Algorisme per detectar decisions incompatibles
}


Detectar la decisions entre companys incompatibles

Quan coneixem la decisió d’un company i la certesa amb que ha pres aquesta decisió llavors és quan es mira si calen aplicar els consensos. Moltes vegades es possible que un jugador decideix anar a la pilota i un dels seus companys decideix posar-se a la seva zona de defensa, en aquests cas cada jugador a pres una decisió completament independent. Quan les decisions preses per dos jugadors no s’interfereixen no calen aplicar els consensos. El problema sorgeix quan dos jugadors realitzen decisions que entren amb conflicte, com per exemple, que dos jugadors decideixen atacar. Les decisions que són conflictives són les següents:
 
Jugador \ Company
XUTAR
ATACAR
ANAR_PILOTA
RECUPERAR
XUTAR Conflicte Conflicte Conflicte  
ATACAR Conflicte Conflicte Conflicte  
ANAR_PILOTA Conflicte Conflicte Conflicte Conflicte
RECUPERAR     Conflicte Conflicte

La resta de possibles accions a realitzar (ATURAR, DEFENSAR, COBRIR, … ) no són conflictives amb cap altre acció.

Si no és produeix cap tipus de conflicte el jugador ha de realitzar l’acció de a decidit fer, però si existeix un conflicte amb un altre jugador llavors s’han d’aplicar consensos.

El codi per detectar les incompatibilitats és el següent:



switch(decidit) // decisió presa per jugador
{
    case XUTAR:
        /* Mirar si hi ha incompatibilitats entre les decisions del company */
        switch(decisio_company)
        {
            case XUTAR:
            case ANAR_PILOTA:
            case ATACAR:
                // Algorisme de consensos
                break;
        }
        break;

    case ANAR_PILOTA:
        /* Mirar si hi ha incompatibilitats entre les decisions del company */
        switch(decisio_company)
        {
            case XUTAR:
            case RECUPERAR:
            case ANAR_PILOTA:
            case ATACAR:
                // Algorisme de consensos
                break;
        }
        break;

    case RECUPERAR:
        /* Mirar si hi ha incompatibilitats entre les decisions del company */
        switch(decisio_company)
        {
            case RECUPERAR:
            case ANAR_PILOTA:
                // Algorisme de consensos
                break;
        }
        break;

    case ATACAR:
        /* Mirar si hi ha incompatibilitats entre les decisions del company */
        switch(decisio_company)
        {
            case XUTAR:
            case ANAR_PILOTA:
            case ATACAR:
                // Algorisme de consensos
                break;
        }
        break;
}


Consensuar la decisió amb els companys

L’aplicació de consensos consisteix en comparar la certesa de les decisions de dos jugadors tenint en compte el prestigi i la necessitat dels jugadors. Per fer aquesta comparació realitza el producte de la certesa de la decisió presa per el jugador amb la seva necessitat i es compara amb el producte de la certesa de la decisió del company amb el prestigi que el jugador dona al seu company. Si el jugador que realitza la comparació obté un valor de certesa més alt que el seu company llavors no cal canviar la decisió del jugador. En canvi si la certesa obtinguda per el jugador és inferior a la certesa del seu company llavors el jugador ha de canviar de decisió. Cada tipus de jugador té definida una segona opció per defecte que està guardada a la variable Segona_decisio i que ha estat assignada a la fase d’inicialitzacions, per exemple, la opció per defecte del davanter és anar a la zona d’atac.

El codi següent és l’encarregat de realitzar els consensos. Les variables canvi_decisio, ID_canvi_decisio i decisio_canvi_decisio són utilitzades les l’algorisme de consensos adaptatius.



if (decisions[decidit]*consensos[RobotID]<certesa_company*consensos[id_company])
{ // canviem la nostra decisió
    decidit=Segona_decisio;
    canvi_decisio=true;
    ID_canvi_decisio=id_company;
    decisio_canvi_decisio=decisio_company;
}

Algorisme adaptatiu de Prestigi i necessitat

Cada jugador a mesura que es desenvolupa el partit va variant la seva necessitat i el prestigi que té dels altres companys.

Necessitat

El concepte de necessitat fa referència a la necessitat que té el robot per anar a la pilota. Per exemple, si es tracta d’un defensor i la pilota està en la zona d’atac del camp contrari, la necessitat d’aquest jugador és molt baixa ja que no li correspon a ell anar a buscar la pilota.

La necessitat anirà variant a cada execució depenent de cada tipus de jugador la necessitat serà diferent.

S’han definit unes funcions de necessitat per a cada tipus de jugador:

El codi d’aquesta funció és el següent:


if (portacont.x<0)
{
    if (pos.x>f.DIST_ZO_MIN) res=1;
    else res=(1/(f.DIST_ZO_MIN-portacont.x))*pos.x+(1-f.DIST_ZO_MIN/(f.DIST_ZO_MIN-portacont.x));
}
else
{
    if (pos.x<-f.DIST_ZO_MIN) res=1;
    else res=(-1/(f.DIST_ZO_MIN-portacont.x))*pos.x+(1-f.DIST_ZO_MIN/(f.DIST_ZO_MIN -portacont.x));
}

El codi de la necessitat del mig dret és el següent:


double res;
double inc=0.15;
if (portaprop.x>0)
{
    if (pos.y>f.DIST_OB_MAX-inc) res=1;
    else res=(1/(f.DIST_OB_MAX+0.76-inc))*pos.y+(1-(f.DIST_OB_MAX-inc)/(f.DIST_OB_MAX+0.76-inc));
}
else
{
    if (pos.y<-f.DIST_OB_MAX+inc) res=1;
    else res=(-1/(f.DIST_OB_MAX-inc+0.76))*pos.y+(1-(f.DIST_OB_MAX-inc)/(f.DIST_OB_MAX+0.76-inc));
}
return res;

El codi de la necessitat del mig esquerra és el següent:


double res;
double inc=0.15;
if (portaprop.x<0)
{
    if (pos.y>f.DIST_OB_MAX-inc) res=1;
    else res=(1/(f.DIST_OB_MAX-inc+0.76))*pos.y+(1-(f.DIST_OB_MAX-inc)/(f.DIST_OB_MAX+0.76-inc));
}
else
{
    if (pos.y<-f.DIST_OB_MAX+inc) res=1;
    else res=(-1/(f.DIST_OB_MAX-inc+0.76))*pos.y+(1-(f.DIST_OB_MAX-inc)/(f.DIST_OB_MAX+0.76-inc));
}
return res;

El codi de la funció necessitat pel davanter és el següent:


double res;
if (portaprop.x>0)
{
    if (pos.x<-f.DIST_ZO_MIN) res=1;
    else res=(-1/(f.DIST_ZO_MIN+portaprop.x))*pos.x+(1-f.DIST_ZO_MIN/(f.DIST_ZO_MIN+portaprop.x));
}
else
{
    if (pos.x>f.DIST_ZO_MIN) res=1;
    else res=(1/(f.DIST_ZO_MIN+portaprop.x))*pos.x+(1-f.DIST_ZO_MIN/(f.DIST_ZO_MIN+portaprop.x));
}
return res;

Prestigi

El prestigi que un jugador i té sobre un company j es basa en calcular la necessitat que té el jugador j per anar a la pilota en la situació de joc corresponent. Aquest prestigi, que s’inicialitza amb un valor arbitrari (0.5), anirà canviant a mesura que es vagi desenvolupant el joc i sempre que es produeixin interferències entre les accions que vol fer el jugador i i el j, les interferències possibles s’han explicat anteriorment. L’algorisme de canvi de prestigi per un agent funciona de la següent manera:


if (decisions[decidit]*consensos[RobotID]<certesa_company*consensos[id_company])
{ // canviem la nostra decisió
    decidit=Segona_decisio;
    canvi_decisio=true;
    ID_canvi_decisio=id_company;
    decisio_canvi_decisio=decisio_company;
}


if ((canvi_decisio)&&(id_company==ID_canvi_decisio))
{
    if (decisio_company==decisio_canvi_decisio)
    {
        switch(id_company)
        {
            case 0: consensos[id_company]=necessitat_porter(pilota,portacont);break;
            case 1: consensos[id_company]=necessitat_defensa(pilota,portacont);break;
            case 2: consensos[id_company]=necessitat_mig_dret(pilota,portaprop);break;
            case 3: consensos[id_company]=necessitat_davanter(pilota,portaprop);break;
            case 4: consensos[id_company]=necessitat_mig_esquerra(pilota,portaprop);break;
        }
    }
    if (consensos[id_company]>1) consensos[id_company]=1;
    if (consensos[id_company]<0) consensos[id_company]=0;
    canvi_decisio=false;
}

ACCIONS

Un cop decidida l’acció a desenvolupar i consensuada amb els diferents agents cal realitzar l’acció que farà la decisió resultant. Hi ha un total d’onze accions possibles, com ja s’ha comentat anteriorment. A continuació s’analitzarà cada acció, amb la qual s’obtindrà el vector resultat, i la velocitat. El vector resultat serà el vector a la posició on ha d’anar el jugador i la velocitat és amb quina velocitat s’ha de moure.

Tots els exemples d’accions que es mostraran a continuació estan definits com a equip propi l’equip de l’oest.

Xutar

El vector resultant serà el vector del jugador a la pilota. Com que cal xutar s’ha d’anar sempre a la velocitat màxima (1.0). La Figura 2 mostra el vector de l’acció xutar.
 



Figura 2. Acció xutar


 
















El codi d’aquesta acció és el següent:



resultat=jo_pilota; // anar a la pilota
velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);
if (abstract_robot.canKick(temps_act))
    abstract_robot.kick(temps_act);

Anar a Pilota

Anar a pilota és una acció on el jugador anirà a buscar la pilota. El jugador es situarà en una posició darrera la pilota per a després poder atacar o xutar. El jugador es situarà en la direcció del vector porteria pròpia – pilota a una distància 0.05 de la pilota i a velocitat màxima. El vector resultant és el que es mostra en la Figura 3 en color negre.

El codi d’aquesta acció és el següent:



pilota_porta=new Vec2(portaprop);
pilota_porta.sub(pilota);
pilota_porta.setr(0.05);
posicio=new Vec2(pilota);
posicio.add(pilota_porta);
resultat=new Vec2(posicio); // Anar a poca distancia darrera la pilota
resultat.sub(jo);
velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);


 
 




Figura 3. Acció anar a pilota


 












Recuperar

Recuperar és una acció de defensa, molt semblant a l’anterior, però augmentant la distància a la pilota per tal de poder posar-se per davant i poder xutar-la. En aquest cas el vector resultant es troba a 0.2 de la pilota. La Figura 4 mostra el vector resultat.
 
 





Figura 4. Acció Recuperar


 
















El codi de l’acció recuperar és el següent:



pilota_porta=new Vec2(portaprop);
pilota_porta.sub(pilota);
pilota_porta.setr(0.2);
posicio=new Vec2(pilota);
posicio.add(pilota_porta);
resultat=new Vec2(posicio); // anar darrera la pilota.
resultat.sub(jo);
velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);

Defensar

L’acció de defensa la realitza únicament el porter. El vector resultant té el sentit del vector porteria – pilota però amb el mòdul limitat a 0.35. La Figura 5 mostra la posició del porter i l’àrea grisa mostra la zona de moviment d’aquest. El porter ha d’anar a velocitat màxima fins que no arribi a la posició final que marca el vector resultat.
 
 




Figura 5. Acció defensar


 








El codi de l’acció és el següent:



pilota_porta=new Vec2(portaprop);
pilota_porta.sub(pilota);
pilota_porta.setr(-0.35); // vector pilota-porta amb un mòdul de 0.35
posicio=new Vec2(portaprop);
posicio.add(pilota_porta);
resultat=new Vec2(posicio);
resultat.sub(jo); // Posició defensa: entre la pilota i la porteria
if (resultat.r<0.05) velocitat=0.0; // Aturar
else velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);
if (abstract_robot.canKick(temps_act))
    abstract_robot.kick(temps_act);

Cobrir

Aquesta acció també la realitza únicament el porter. Quan el porter es troba a fora de la seva àrea aquesta acció el situa dins de l’àrea. El vector resultant, tal i com mostra la Figura 6, serà el vector jo – porteria pròpia i el robot anirà a velocitat màxima.

El codi de l’acció cobrir és el següent:


resultat=jo_portaprop;
velocitat=1.0; // cobrir la porteria
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);


 
 




Figura 6. Acció Cobrir


 












Atacar

Aquesta acció situarà el robot en el sentit del vector pilota – porteria contrària a una distància 0.05 més enrera de la pilota per tal de poder-la xutar. Com que es tracta d’una acció d’atac cal fer-la a velocitat màxima (1.0). La Figura 7 mostra un exemple d’aquest tipus d’acció.
 
 




Figura 7. Acció Atacar


 








El codi d’aquesta acció és:



pilota_porta=new Vec2(portacont);
pilota_porta.sub(pilota);
pilota_porta.setr(-0.05);
posicio=new Vec2(pilota);
posicio.add(pilota_porta);
resultat=new Vec2(posicio); //anar darrera la pilota, encarar-se i xutar
resultat.sub(jo);
velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);

Obert Dreta / Obert Esquerra

Aquestes dues accions són anàlogues i situaran el jugador a la banda dreta o esquerra del camp a la mateixa alçada, en coordenades x, que la pilota. En la Figura 8 veiem els dos laterals que es troben oberts a la dreta i a l’esquerra que s’estan situant a l’alçada de la pilota en x. Aquesta acció es realitzarà a velocitat màxima fins que no arribi a la posició desitjada.

El codi per l’acció Obert Dreta és el següent:



posicio=new Vec2(pilota.x,0.4*portaprop.x/Math.abs(portaprop.x));
resultat=posicio;
resultat.sub(jo); // anar al lateral dret, a l'alçada x de la pilota
if (resultat.r<0.05) velocitat=0.0;
else velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);
if (abstract_robot.canKick(temps_act))
    abstract_robot.kick(temps_act);

El codi per l’acció Obert Esquerra és el següent:



posicio=new Vec2(pilota.x,-0.4*portaprop.x/Math.abs(portaprop.x));
resultat=posicio;
resultat.sub(jo); // anar al lateral esquerra, a l'alçada x de la pilota
if (resultat.r<0.05) velocitat=0.0;
else velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);
if (abstract_robot.canKick(temps_act))
    abstract_robot.kick(temps_act);


 
 




Figura 8. Accions Obert Dreta i Obert Esquerra


 












Zona Atac

Com mostra la Figura 9 , aquesta acció situarà el jugador al camp contrari, a una distància determinada del mig camp en coordenades x, i a l’alçada, en coordenades y, de la pilota. L’acció es realitzarà a velocitat màxima fins que no s’arribi al punt desitjat.
 
 




Figura 9. Acció Zona Atac


 












El codi d’aquesta acció és el següent:



posicio=new Vec2(-0.4*portaprop.x/Math.abs(portaprop.x),pilota.y);
resultat=posicio;
resultat.sub(jo); // anar a zona d'atac, a l'alçada y de la pilota
if (resultat.r<0.05) velocitat=0.0;
else velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);
if (abstract_robot.canKick(temps_act))
    abstract_robot.kick(temps_act);

Zona Defensa

Aquesta acció segueix la mateixa filosofia que l’anterior però en aquest cas no es va al camp contrari si no que el jugador es situa al camp propi a una distància determinada en x i a l’alçada de la pilota en y. La Figura 10 mostra un exemple d’aquesta acció.

El codi d’aquesta acció és el següent:



posicio=new Vec2(0.4*portaprop.x/Math.abs(portaprop.x),pilota.y);
resultat=posicio;
resultat.sub(jo); // anar a zona de defensa
if (resultat.r<0.05) velocitat=0.0;
else velocitat=1.0;
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);
if (abstract_robot.canKick(temps_act))
    abstract_robot.kick(temps_act);


 
 




Figura 10. Acció Zona Defensa


 








Aturar

Aquesta acció és la més simple de totes i es tracta de parar el jugador, és a dir, donar-li velocitat 0. Cal tenir en compte, però, que encara que el robot està parat, s’anirà encarant a la pilota a mesura que aquesta es vagi movent.

El codi d’aquesta acció és el següent:



resultat=jo_pilota;
velocitat=0.0; // para el robot
abstract_robot.setSteerHeading(temps_act, resultat.t);
abstract_robot.setSpeed(temps_act, velocitat);

JOCS DE PROVES

S’han desenvolupat tres jocs de proves diferents (porter, defensa i mig) per tal d’analitzar millor els moviments dels jugadors porter, defensa i mig, independentment. Un quart fitxer de proves (o7kou) serà el que jugarà amb tots els cinc jugadors (porter, defensa, mitjos i davanter). En aquest exemple es podrà apreciar el funcionament dels diversos agents, la presa de decisions utilitzant consensos i el canvi de prestigis dels agents mitjançant l’algoritme adaptatiu.

Tots els jocs de proves s’ha realitzat contra l’equip SchemaDemo. Segons les proves realitzades aquest és un dels millors equips dels que hi ha en els d’exemple.

Per a observar l’acció que està realitzant cada jugador cal activar l’opció robot state del menú view.

Porter

El fitxer de proves porter.bat mostrarà el funcionament del porter. Tal i com mostra la Figura 11 es jugarà u contra cinc contraris.

El porter realitzarà l’acció defensar, cobrir i xutar tal i com s’ha explicat anteriorment.
 
 





Figura 11. Exemple de proves porter.bat


 












Defensa

El fitxer defensa.bat mostrarà el funcionament del defensa i el porter jugant contra cinc contraris. Les accions del defensa són treu la pilota cap al camp contrari i defensar l’atac dels contraris. La Figura 12 mostra un instant del joc.
 
 





Figura 12. Exemple de proves defensa.bat


 












Mig

En aquest exemple (mig.bat) es veurà el funcionament del mig esquerra juntament amb el defensa i el porter. La Figura 13 mostra un exemple d’execució.
 
 





Figura 13. Exemple de proves mig.bat


 












Ou7kou

En aquest exemple (fitxer ou7kou.bat) podem observar el joc de tots cinc components de l’equip. Aquesta execució és on s’observa millor el consens de les decisions entre els jugadors i la variació dels prestigis de cada agent en funció del desenvolupament del joc. La Figura 14 mostra un instant del joc. El davanter està en posició de xutar, els dos mitjos es troben oberts a la seva banda corresponent i el defensor es troba a la zona de defensa. En aquesta jugada es produeix un conflicte entre el davanter i el mig esquerra ja que inicialment tots dos volen anar a la pilota. El davanter té major necessitat d’anar a la pilota que el mig esquerra. donat que el valor de la decisió multiplicat per la necessitat del mig esquerra és menor que el prestigi que té el mig esquerra del davanter, aleshores el mig canviarà la seva decisió deixant que sigui el davanter el que vagi a la pilota.
 
 





Figura 14. Exemple de proves ou7kou.bat