package sos.mas; import jade.content.ContentElement; import jade.content.lang.Codec; import jade.content.lang.sl.SLCodec; import jade.content.onto.Ontology; import jade.content.onto.basic.Action; import jade.core.AID; import jade.core.Agent; import jade.core.behaviours.OneShotBehaviour; import jade.core.behaviours.ParallelBehaviour; import jade.core.behaviours.SequentialBehaviour; import jade.domain.DFService; import jade.domain.FIPAAgentManagement.DFAgentDescription; import jade.domain.FIPAAgentManagement.ServiceDescription; import jade.domain.FIPAException; import jade.domain.FIPANames; import jade.domain.JADEAgentManagement.ShutdownPlatform; import jade.lang.acl.ACLMessage; import jade.lang.acl.MessageTemplate; import jade.proto.AchieveREInitiator; import jade.util.Logger; import sos.mas.ontology.GameOntology; import sos.mas.ontology.Guilty; import sos.mas.ontology.Prisoner; import sos.mas.ontology.Round; import java.util.Date; import java.util.Vector; public class GamemasterAgent extends Agent { private void out(String text, Object... args) { System.err.print("[" + getLocalName() + "] "); System.err.println(String.format(text, args)); } private Logger logger; private SubscriptionResponder subscriptionResponder; private Codec codec = new SLCodec(0); private Ontology ontology = GameOntology.getInstance(); private GameHistory game; @Override protected void setup() { try { logger = Logger.getMyLogger(getAID().getLocalName()); out("Starting"); getContentManager().registerLanguage(codec, FIPANames.ContentLanguage.FIPA_SL0); getContentManager().registerOntology(ontology); handleArguments(); registerService(); subscriptionResponder = new SubscriptionResponder(this); SequentialBehaviour gameRoundBehaviours = new SequentialBehaviour(this); for (int i = 0; i < game.getIterations(); i++) { gameRoundBehaviours.addSubBehaviour(new BeginRoundBehaviour()); } ParallelBehaviour runGameBehaviour = new ParallelBehaviour(this, ParallelBehaviour.WHEN_ANY); runGameBehaviour.addSubBehaviour(subscriptionResponder); runGameBehaviour.addSubBehaviour(gameRoundBehaviours); SequentialBehaviour behaviour = new SequentialBehaviour(this); behaviour.addSubBehaviour(runGameBehaviour); behaviour.addSubBehaviour(new EndGameBehaviour()); addBehaviour(behaviour); } catch (FIPAException fe) { fe.printStackTrace(); doDelete(); } } private void handleArguments() { Object[] args = getArguments(); if (args == null || args.length < 3 || args.length > 3) { out("Need to supply the names of the two prisoner agents and the number of iterations."); doDelete(); return; } AID prisoner1 = new AID((String) args[0], AID.ISLOCALNAME); AID prisoner2 = new AID((String) args[1], AID.ISLOCALNAME); int iterations = Integer.parseInt((String) args[2]); if (iterations < 1) { out("Invalid value for iterations (must be > 0 but was %d)", iterations); doDelete(); } game = new GameHistory(prisoner1, prisoner2, iterations); } private void registerService() throws FIPAException { DFAgentDescription dfd = new DFAgentDescription(); dfd.setName(getAID()); ServiceDescription sd = new ServiceDescription(); sd.setName(getLocalName()); sd.setType("prisoners-dilemma-gamemaster"); sd.addOntologies(ontology.getName()); sd.addLanguages(FIPANames.ContentLanguage.FIPA_SL0); dfd.addServices(sd); DFService.register(this, dfd); } @Override protected void takeDown() { out("Stopping"); } // // Behaviours // private class SubscriptionResponder extends jade.proto.SubscriptionResponder { public SubscriptionResponder(Agent a) { super(a, MessageTemplate.and( MessageTemplate.or(MessageTemplate.MatchPerformative(ACLMessage.SUBSCRIBE), MessageTemplate.MatchPerformative(ACLMessage.CANCEL)), MessageTemplate.MatchProtocol(FIPANames.InteractionProtocol.FIPA_SUBSCRIBE))); } @Override protected ACLMessage handleSubscription(ACLMessage subscription) { // handle a subscription request // if subscription is ok, create it try { createSubscription(subscription); } catch (Exception e) { ACLMessage refuse = new ACLMessage(ACLMessage.REFUSE); refuse.addReceiver(subscription.getSender()); refuse.setProtocol(FIPANames.InteractionProtocol.FIPA_SUBSCRIBE); return refuse; } // if successful, should answer (return) with AGREE; otherwise with REFUSE or NOT_UNDERSTOOD ACLMessage agree = new ACLMessage(ACLMessage.AGREE); agree.addReceiver(subscription.getSender()); agree.setProtocol(FIPANames.InteractionProtocol.FIPA_SUBSCRIBE); return agree; } public void notify(ACLMessage inform) { // this is the method you invoke ("call-back") for creating a new inform message; // it is not part of the SubscriptionResponder API, so rename it as you like // go through every subscription Vector subs = getSubscriptions(); for (int i = 0; i < subs.size(); i++) ((jade.proto.SubscriptionResponder.Subscription) subs.elementAt(i)).notify(inform); } } private class BeginRoundBehaviour extends AchieveREInitiator { public BeginRoundBehaviour() { super(GamemasterAgent.this, null); } @Override protected Vector prepareRequests(ACLMessage request) { ACLMessage query = new ACLMessage(ACLMessage.QUERY_IF); query.addReceiver(game.getPrisoner1().getAgent()); query.addReceiver(game.getPrisoner2().getAgent()); query.setOntology(ontology.getName()); query.setLanguage(FIPANames.ContentLanguage.FIPA_SL0); query.setProtocol(FIPANames.InteractionProtocol.FIPA_QUERY); query.setReplyByDate(new Date(System.currentTimeMillis() + 10000)); try { myAgent.getContentManager().fillContent(query, new Guilty()); Vector<ACLMessage> result = new Vector<ACLMessage>(1); result.add(query); return result; } catch (Exception e) { e.printStackTrace(); return null; } } private Guilty extracAnswerContent(Object notification) { ACLMessage inform = (ACLMessage) notification; try { ContentElement content = getContentManager().extractContent(inform); if (!(content instanceof Guilty)) { out("ERROR: not instance of Guilty"); return null; } return (Guilty) content; } catch (Exception e) { e.printStackTrace(); return null; } } @Override protected void handleFailure(ACLMessage failure) { if (failure.getSender().equals(myAgent.getAMS())) // FAILURE notification from the JADE runtime: the receiver does not exist out("Responder does not exist"); else out("Agent %s failed to perform the requested action", failure.getSender().getName()); } @Override protected void handleAllResultNotifications(Vector notifications) { out("handling %d result notifications", notifications.size()); if (notifications.size() < 0) { out("ERROR: too few answers to query"); return; } if (notifications.size() > 2) out("WARNING: more than two answers to query"); String id = ((ACLMessage) notifications.get(0)).getConversationId(); Round currentRound = game.newRound(id); Guilty guilty1 = extracAnswerContent(notifications.get(0)); Guilty guilty2 = extracAnswerContent(notifications.get(1)); if (game.getPrisoner1().getAgent().equals(guilty1.getPrisoner().getAgent())) { currentRound.setConfession1(guilty1.getConfession()); currentRound.setConfession2(guilty2.getConfession()); } else { currentRound.setConfession1(guilty2.getConfession()); currentRound.setConfession2(guilty1.getConfession()); } try { ACLMessage inform = new ACLMessage(ACLMessage.INFORM); inform.setProtocol(FIPANames.InteractionProtocol.FIPA_SUBSCRIBE); inform.setLanguage(FIPANames.ContentLanguage.FIPA_SL0); inform.setOntology(ontology.getName()); getContentManager().fillContent(inform, currentRound); subscriptionResponder.notify(inform); } catch (Exception e) { e.printStackTrace(); } } } private class EndGameBehaviour extends OneShotBehaviour { private EndGameBehaviour() { super(GamemasterAgent.this); } @Override public void action() { int[] yearsInJail = game.calculatePoints(); out("%s got %d years in jail.", game.getPrisoner1().getAgent().getLocalName(), yearsInJail[0]); out("%s got %d years in jail.", game.getPrisoner2().getAgent().getLocalName(), yearsInJail[1]); Prisoner winner = null; if (yearsInJail[0] > yearsInJail[1]) winner = game.getPrisoner2(); else if (yearsInJail[0] < yearsInJail[1]) winner = game.getPrisoner1(); if (winner != null) out("%s is the winner", winner.getAgent().getLocalName()); else out("the game is a draw"); try { ShutdownPlatform shutdown = new ShutdownPlatform(); Action action = new Action(); action.setActor(myAgent.getAMS()); action.setAction(shutdown); ACLMessage message = new ACLMessage(ACLMessage.REQUEST); message.setSender(myAgent.getAID()); message.addReceiver(myAgent.getAMS()); message.setProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST); message.setLanguage(FIPANames.ContentLanguage.FIPA_SL0); message.setOntology(jade.domain.JADEAgentManagement.JADEManagementOntology.NAME); myAgent.getContentManager().registerOntology(jade.domain.JADEAgentManagement.JADEManagementOntology .getInstance()); myAgent.getContentManager().fillContent(message, action); myAgent.send(message); } catch (Exception e) { e.printStackTrace(); } } } }