Login

Tweet recenti ...

By A Web Design Company

dadi200x150Iniziamo, con questo articolo, una nuova serie di pubblicazioni relative agli agenti.

Gli agenti sono dei componenti software che possiedono determinate proprietà quali, l'autonomia, la capacità di cooperazione ed altre ancora. In questo documento ci concentreremo solo sugli aspetti di comunicazione, utilizzando una delle numerose piattaforme disponibili per sviluppare sistemi basati su agenti: JADE.

Nell'esempio che andremo ad esaminare avremo due agenti che, comunicando tra di loro, giocheranno al noto gioco "indovina il numero".

Le regole del gioco sono molto semplici: il primo giocatore pensa un numero intero tra uno e un valore massimo prefissato (nell'esempio tale valore è 10.000), il secondo tenta di indovinare qual è il numero e riceve in risposta dal primo se il suo tentativo è superiore al numero "misterioso", oppure se è uguale o se ha indovinato.

L'algoritmo per risolvere questo problema è molto semplice ed è la classica ricerca dicotomica: si va a metà dell'intervallo di incertezza e, in base alla risposta (maggiore o minore) si restringe ulteriormente l'intervallo, andando di nuovo alla sua metà e via dicendo. Si dimostra facilmente che il numero massimo di tentativi cresce con l'intero superiore del logaritmo in base 2 del valore più alto possibile (nel nostro caso è quindi pari a 14).

L'implementazione effettuata sulla piattaforma JADE è molto semplice e consiste in due agenti (che sono dei semplici contenitori) a ciascuno dei quali è assegnato un behaviour che al suo interno contiene un automa stati finiti che gli consente di gestire le varie situazioni di gioco.

Il diagramma degli stati è uguale per entrambi i giocatori: si parte da uno stato iniziale che corrisponde al primo tentativo, si passa ad uno stato in cui si permane per tutti tentativi sbagliati successivi al primo e poi si passa in uno stadio finale in cui due giocatori esultano e terminano il gioco.

Lo stato "primo tentativo"

In questo stato il primo giocatore genera casualmente il numero da indovinare e comunica al secondo giocatore qual è il valore massimo ammissibile per tale numero (valore che nell'esempio è prefissato a 10.000).

Il codice che genera il numero casuale, comunica il massimo possibile e passa allo stato successivo, per il giocatore numero uno, ossia quello che estrae il numero da indovinare, è il seguente (classe QuizB.java):

 

public QuizB(Agent a, long max) {

super(a);

this.max = max;

this.mystery = (long) (Math.floor(Math.random() * max)) + 1;

this.state = PRIMO_TENTATIVO;

}

public void action() {

switch (state) {

case PRIMO_TENTATIVO:

ACLMessage msg = new ACLMessage(ACLMessage.INFORM);

msg.setContent(Long.toString(max));

msg.addReceiver(new AID("con", AID.ISLOCALNAME));

myAgent.send(msg);

state = ATTESA_RISPOSTA;

System.out.println(" - " + myAgent.getLocalName() + " sent: "

+ msg.getContent());

block();

break;

[...]

Come è semplice notare, nel costruttore viene generato il numero casuale mentre nel metodo action(), grazie ad un'istruzione switch che viene utilizzata per far funzionare la macchina a stati finiti che permette all'agente di evolvere, viene impacchettato il messaggio e spedito al destinatario (a cui, per semplicità, è stato assegnato il nome di "con" abbreviazione di concorrente).

Dopo aver spedito il messaggio il sistema cambia di stato, passa lo stato in cui si attende un tentativo dall'altro giocatore e quindi blocca l'agente in attesa di un evento.

Per semplicità sono state omesse le righe di codice successive relative agli altri stati.

Il codice relativo al secondo giocatore è invece reperibile nella classe AnswB.java ed è molto simile al precedente:

public AnswB(Agent a) {

super(a);

this.low = 1;

this.state = PRIMO_TENTATIVO;

}

 

public void action() {

switch (state) {

case PRIMO_TENTATIVO:

ACLMessage msg = myAgent.receive();

if (msg != null) {

System.out.println(" - " + myAgent.getLocalName()

+ " received: " + msg.getContent());

String res = msg.getContent();

long max = Long.parseLong(res);

this.max = max;

this.high = max;

lastGuess = (long) Math.floor(((high - low) / 2) + low);

msg = new ACLMessage(ACLMessage.INFORM);

msg.setContent(Long.toString(lastGuess));

msg.addReceiver(new AID("quiz", AID.ISLOCALNAME));

myAgent.send(msg);

state = TENTATIVI_SUCCESSIVI;

System.out.println(" - " + myAgent.getLocalName() + " sent: "

+ msg.getContent());

block();

}

break;

[...]

Anche in questo caso nel costruttore vengono eseguite delle operazioni di inizializzazione e poi si passa al metodo action() che si occupa di ricevere un messaggio, leggerne il valore e memorizzarlo come il numero massimo (variabili che, in quest'esempio, non sarà più utilizzata). Viene quindi eseguito il primo tentativo prendendo il valore centrale dell'intervallo tra uno e il massimo appena letto. Questo valore viene comunicato al primo giocatore che, per comodità, viene identificato come "quiz".

Dopo l'invio del messaggio il secondo giocatore (il secondo agente) passa nello stato relativo ai tentativi successivi.

I tentativi successivi

Il codice per i tentativi successivi, sebbene più complesso che nel caso del primo, è comunque piuttosto semplice: il primo giocatore riceverà il tentativo dal secondo, lo valuterà e gli risponderà di conseguenza (sei troppo alto, troppo basso o indovinato). Il secondo giocatore, ricevuta una risposta di troppo alto o troppo basso calcolerà il nuovo intervallo e il suo valore centrale e lo comunicherà al primo, avviando una nuova iterazione dello stato. Se invece avrà ricevuto la comunicazione di aver indovinato il numero segreto invierà un messaggio di esultanza e passerà nello stato finale che eseguirà le operazioni di finalizzazione e poi distruggerà l'agente.

Anche il primo giocatore, nel caso in cui il secondo indovinasse, procederà con un cambio di stato per finalizzare quanto necessario è poi autodistruggersi (nel senso di agente, ovviamente).

Il codice relativo al primo giocatore si trova interamente nel metodo action() di QuizB.java ed è:

 

[...]

case ATTESA_RISPOSTA:

msg = myAgent.receive();

if (msg != null) {

System.out.println(" - " + myAgent.getLocalName()

+ " received: " + msg.getContent());

 

long guess = Long.parseLong(msg.getContent());

 

String answ;

if (guess > mystery) {

answ = ">";

} else if (guess < mystery) {

answ = "<";

} else {

answ = "=";

state = FINE;

}

 

ACLMessage reply = msg.createReply();

reply.setPerformative(ACLMessage.INFORM);

reply.setContent(answ);

myAgent.send(reply);

System.out.println(" - " + myAgent.getLocalName() + " sent: "

+ reply.getContent());

block();

}

break;

[...]

 

Il codice è facilmente leggibile: l'agente rimane in attesa di ricevere un messaggio e da questo estrae il tentativo del secondo giocatore. Il numero fornito dall'altra gente viene confrontato con quello segreto che il primo giocatore conosce e viene prodotta una risposta (">" per un tentativo troppo alto, "<" per uno troppo basso e "=" nel caso sia stato indovinato il numero misterioso) che viene inviata al secondo agente (al secondo giocatore).

Per quanto riguarda quest'ultimo, il metodo è lo stesso ma della classe AnswB.java:

 

[...]

case TENTATIVI_SUCCESSIVI:

msg = myAgent.receive();

if (msg != null) {

System.out.println(" - " + myAgent.getLocalName()

+ " received: " + msg.getContent());

 

String res = msg.getContent();

 

String answ;

if (res.equalsIgnoreCase(">")) {

high = lastGuess;

lastGuess = (long) Math.floor(((high - low) / 2) + low);

answ = Long.toString(lastGuess);

} else if (res.equalsIgnoreCase("<")) {

low = lastGuess;

lastGuess = (long) Math.floor(((high - low) / 2) + low);

answ = Long.toString(lastGuess);

} else {

answ = "HO VINTOOOOOOOO!!!!";

state = FINE;

}

ACLMessage reply = msg.createReply();

reply.setPerformative(ACLMessage.INFORM);

reply.setContent(answ);

myAgent.send(reply);

System.out.println(" - " + myAgent.getLocalName() + " sent: "

+ reply.getContent());

block();

}

break;

 

[...]

Anche in questo caso l'agente rimane in attesa di un messaggio e quando lo riceve lo decodifica utilizzando l'informazione ricevuta per stabilire un nuovo intervallo di indeterminazione di cui calcola il valore centrale e lo comunica al primo giocatore.

Entrambi gli agenti, nel caso in cui sia stato indovinato il numero segreto, cambiano di stato e passano alle attività di finalizzazione (che per semplicità non riportiamo).

Conclusioni

Questo semplice esempio mostra come far svolgere un dialogo fra due agenti JADE. È facilmente intuibile che di norma gli agenti non si comportano in una maniera così semplicemente sincrona ma realizzano sistemi di complessità elevata (ecosistemi di agenti).

Il vero problema quando si utilizzano tecnologie basate su agenti è la metodologia di analisi e, soprattutto, di progettazione. È essenziale, infatti, che si concepiscano tali ecosistemi mediante sofisticate tecniche ingegneristiche che consentano di ottenere un risultato di cui sia possibile determinare o imporre le qualità desiderate.

Logica dei Sistemi dell'ing. Luca Lezzerini è a vostra disposizione per supportarvi nella realizzazione e nella progettazione di sistemi complessi basati su agenti, sia sulla piattaforma JADE che in altri ambienti.

I sorgenti dell'esempio sopra discusso sono disponibili in formato zip.