Si consideri l'esempio dell'asta già presentato durante il corso [1] e vediamo come si potrebbe ridefinirlo attraverso l'uso delle classi del package JAM.
In un'asta possiamo riconoscere due ruoli principali, il banditore ed il cliente. Solitamente alcuni clienti si contendono un oggetto effettuando le proprie offerte al banditore. Il cliente che effetuerà l'offerta più alta vince l'asta (Figura 2).
I vari rilanci seguono un preciso schema, ogni offerta deve essere più alta della migliore offerta attuale. Se tale oferta è accettata dal banditore allora quella diventa la nuova migliore offerta. Se un cliente ritiene che la migliore offerta corrente è incompatibile con il suo budget a disposizione, si ritira dalla competizione. Se alla fine nessuno effettua un rilancio, il banditore incomincia a battere il martello e al terzo battito aggiudica l'oggetto al migliore offerente di quel momento. Questo è quello che avviene in una gara d'asta dal vivo. Nella nostra simulazione supponiamo che ogni cliente possa chiedere la migliore offerta corrente e quindi decidere se rilanciare oppure no a seconda del budget a disposizione. Lo schema dell'interazione tra un cliente e il battitore è presentato nella Figura 3.
Un agente in JAM è definito mediante l'estensione di una opportuna classe, la classe JAMAgent. Questa mette a disposizione tutte le primitive per inviare e ricevere messaggi da altri agenti presenti in un dato momento nello RAM a cui esso appartiene. Il comportamento di un agente è definito mediante un oggetto di tipo JAMBehaviour. Tale oggetto contiene un metodo denominato action che viene eseguito in un thread all'avvio dell'esecuzione dell'agente. L'azione definita può essere eseguito una sola volta o ripetuto ciclicamente sino al raggiungimento di una determinata situazione.
Le classi che definiscono il comportamento e l'agente Banditore potrebbero essere, ad esempio, le seguenti.
class BanditoreAstaBehaviour extend JAMWhileBehaviour { [...] public BanditoreAstaBehaviour(JAMAgent myAgent) { super(myAgent); } [...] public void action() { Message msg = myAgent.receive(); if (msg.getType() == MessageType.REQUEST) { if (msg.getContent().equals("ATTUALE OFFERTA?")) { Message answerRequest = new Message(MessageType.INFORM); answerRequest.setSender(myAgent.getID()); answerRequest.setReceiver(msg.getSender()); if ((msg.getSender()).equals(miglioreOfferta.getOfferente())) { battuta++; System.out.println(miglioreOfferta.getOfferta() + " e " + battuta + " per " + miglioreOfferente.getOfferente() + "!"); if (battuta == MAX_BATTUTE) { System.out.println("Aggiudicato per " + miglioreOfferta.getOfferta() + " a " + miglioreOfferta.getOfferente() +"!"); answerRequest.setContent("AGGIUDICATO"); answerRequest.setExtraArgument(miglioreOfferta); myAgent.send(answerRequest); done(); } else { System.out.println("Ci sono altre offerte?"); sleep(TEMPO_ATTESA); if (myAgent.areThereMessage()) battuta = 0; answerRequest.setContent("MIGLIORE OFFERTA"); answerRequest.setExtraArgument(miglioreOfferta); myAgent.send(answerRequest); } } else { answerRequest.setContent("MIGLIORE OFFERTA"); answerRequest.setExtraArgument(miglioreOfferta); myAgent.send(answerRequest); } } else { Message answerRequest = new Message(MessageType.REFUSE); answerRequest.setSender(myAgent.getID()); answerRequest.setReceiver(msg.getSender()); answerRequest.setContent("REQUEST NON SODDISFACIBILE"); answerRequest.setExtraArgument(msg); myAgent.send(answerRequest); } } else if (msg.getType() == MessageType.QUERY-IF) { if (msg.getContent().equals("RILANCIO")) { Offerta rilancio = (Offerta) msg.getExtraArgument(); Message answerQueryIf = new Message(MessageType.INFORM); answerRequest.setSender(myAgent.getID()); answerRequest.setReceiver(msg.getSender()); if (miglioreOfferta.migliore(rilancio)) { battuta = 0; System.out.println(miglioreOfferta() + " per " + miglioreOfferta.getOfferente()); answerRequest.setContent("RILANCIO ACCETTATO"); } else answerNewBid.setContent("RILANCIO RIFIUTATO"); myAgent.send(answerQueryIf); } else { Message answerQueryIf = new Message(MessageType.REFUSE); answerQueryIf.setSender(myAgent.getID()); answerQueryIf.setReceiver(msg.getSender()); answerQueryIf.setContent("QUERY_IF NON SODDISFACIBILE"); answerQueryIf.setExtraArgument(msg); myAgent.send(answerQueryIf); } } else if (msg.getType() == MessageType.INFORM) { if (contentMsg.equals("RINUNCIA")) { System.out.println(msg.getSender() + " si ritira dalla competizione!"); } else { Message answerInform = new Message(MessageType.NOT-UNDERSTOOD); answerInform.setSender(myAgent.getID()); answerInform.setReceiver(msg.getSender()); answerInform.setContent("NON CAPISCO"); answerInform.setExtraArgument(msg); myAgent.send(answerInform); } } else { Message notUnderstoodMsg = new Message(MessageType.NOT-UNDERSTOOD); notUnderstoodMsg.setSender(myAgent.getID()); notUnderstoodMsg.setReceiver(msg.getSender()); notUnderstoodMsg.setContent("NON CAPISCO"); notUnderstoodMsg.setExtraArgument(msg); myAgent.send(notUnderstoodMsg); } } } class Banditore extend JAMAgent { [...] public Banditore(...) { addBehaviour(new BanditoreAstaBehaviour(this)); } [...] }
Le classi che definiscono, invece, il comportamento e l'agente Cliente potrebbero essere, ad esempio, le seguenti.
class ClientAstaBehaviour extend JAMWhileBehaviour { [...] public ClientAstaBehaviour(JAMAgent myAgent) { super(myAgent); } [...] public void action() { Message request = new Message(MessageType.REQUEST); request.setSender(myAgent.getID()); request.setReceiver(((ClientAgent)myAgent).getMyBanditoreID()); request.setContent("OFFERTA ATTUALE?"); myAgent.send(request); Message answerRequest = myAgent.receive(MessageType.INFORM, (((ClientAgent)myAgent).getMyBanditoreID())); if (answerRequest.getContent("AGGIUDICATO")) { System.out.println("Sono il vincitore!!"); Offerta offertaVincitrice = (Offerta) msg.getExtraArgument(); System.out.println("Con un'offerta di " + offertaVincitrice.getOfferta()); done(); } else if (answerRequest.getContent().equals("MIGLIORE OFFERTA")) { Offerta offertaCorrente = (Offerta) msg.getExtraArgument(); if (!(offertaCorrente.getOfferente().equals(myAgent.getName()))) { if (offertaCorrente.getOfferta() < ((ClientAgent)myAgent).getBudget() - RILANCIO) { Offerta rilancio = new Offerta (myAgent.getID(), current.getOfferta() + (int)(Math.random() * RILANCIO)); Message rilancioMsg = new Message(MessageType.QUERY-IF); rilancioMsg.setSender(myAgent.getID()); rilancioMsg.setReceiver((((ClientAgent)myAgent).getMyBanditoreID())); rilancioMsg.setContent("RILANCIO"); rilancioMsg.setExtraArgument(rilancio); myAgent.send(rilancioMsg); Message answerRilancio = myAgent.receive(MessageType.INFORM, (((ClientAgent)myAgent).getMyBanditoreID())); if (answerRilancio.getContent().equals("RILANCIO ACCETTATO")) sleep((int)(Math.random() * DELTA ); else if (!answerRilancio.getContent().equals("RILANCIO RIFIUTATO")) { Message notUnderstoodMsg = new Message(MessageType.NOT_UNDERSTOOD); notUnderstoodMsg.setSender(myAgent.getID()); notUnderstoodMsg.setReceiver((((ClientAgent)myAgent).getMyBanditoreID())); notUnderstoodMsg.setContent("NON CAPISCO"); notUnderstoodMsg.setExtraArgument myAgent.send(notUnderstoodMsg); } } else { Message rinunciaMsg = new Message(MessageType.INFORM); rinunciaMsg.setSender(myAgent.getID()); rinunciaMsg.setReceiver((((ClientAgent)myAgent).getMyBanditoreID())); rinunciaMsg.setContent("RINUNCIA"); myAgent.send(rinunciaMsg); System.out.println("Rinuncio alla competizione."); done(); } } else sleep((int)(Math.random() * TEMPO ATTESA); } else { Message notUnderstoodMsg = new Message(MessageType.NOT_UNDERSTOOD); notUnderstoodMsg.setSender(myAgent.getID()); notUnderstoodMsg.setReceiver((((ClientAgent)myAgent).getMyBanditoreID())); notUnderstoodMsg.setContent("NON CAPISCO"); notUnderstoodMsg.setExtraArgument myAgent.send(notUnderstoodMsg); } } } class ClientAgent extend JAMAgent { [...] private AgentID myBanditoreID; private int budget; [...] public AgentID getMYBanditoreID() { ... } public int getBudget() { ... } [...] public ClientAgent(...) { [...] addBehaviour(new ClientAstaBehaviour(this)); } [...] }