home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 07 DecisionMaking Architectures / 01 Isla, Blumberg / Blackboard.java < prev    next >
Encoding:
Java Source  |  2001-09-25  |  8.4 KB  |  221 lines

  1. package bb;
  2.  
  3. import java.util.*;
  4.  
  5. /**
  6. This is our main blackboard class. 
  7.  
  8. The blackboard is really just a hashtable of open missions. The key is the name of the skill
  9. required for the mission (e.g. "ATTACK_CITY") and the value is the mission object itself
  10. which contains specific mission parameters.
  11.  
  12. It also happens that this blackboard is where we do the arbitration. When agents apply for a
  13. mission, the blackboard compiles the list of applications and grants it to the top N most 
  14. relevant agents, where N is determined by the mission itself. The rest of the agents are 
  15. denied, which means that either they have to try again next time, or they have to just 
  16. continue what they're currently doing.
  17.  
  18. NOTE that for the sake of efficiency, ONLY open missions, i.e. missions that are still looking
  19. for members, are kept on the blackboard. Once the mission is filled, it is removed. This means
  20. that sometimes we have to put the mission back on when, say, one of the members dies.
  21.  
  22. @author naimad
  23. */
  24.  
  25. public class Blackboard {
  26.  
  27.     /*
  28.     The hashtable itself. Note that the actual implementation used is a 
  29.     hashtable of VECTORS (which are the basic Java LIST structure). 
  30.     This is because for every type of skill that might be posted, there
  31.     will often be multiple missions.
  32.     */
  33.     Hashtable openMissions;
  34.     int team;
  35.  
  36.     public Blackboard(int team) {
  37.         openMissions =  new Hashtable();
  38.         this.team = team;
  39.     }
  40.     
  41.     
  42.     //----------------------------MISSION STATUS------------------------
  43.  
  44.     /*
  45.     Used by producers of missions to put it on the blackboard.
  46.     */
  47.     public void addMission(Mission mission) {
  48.         Vector v = (Vector)openMissions.get(mission.getSkillName());
  49.         if (v==null) {
  50.             v = new Vector();
  51.             openMissions.put(mission.getSkillName(), v);
  52.         }
  53.         if (!v.contains(mission)) v.addElement(mission);
  54.     }
  55.  
  56.     /*
  57.     Used by producers of missions to remove the mission, either because of 
  58.     completion, or because the producer of the mission died.
  59.     */
  60.     public void removeMission(Mission mission) {
  61.         Vector v = (Vector)openMissions.get(mission.getSkillName());
  62.         if (v!=null && v.contains(mission)) {
  63.             v.remove(mission);
  64.         }
  65.     }
  66.  
  67.     /*
  68.     Returns a list of missions that call for a specific kind of skill.
  69.     It all depends on the skill NAME, by the way, not the specific contents
  70.     or implementation of the skill object itself. For example, different 
  71.     agents might go about performing the same skill in different ways.
  72.     */
  73.     public Vector getMissionsForSkill(Skill skill) {
  74.         Vector v = (Vector)openMissions.get(skill.getName());
  75.         if (v==null) {
  76.             v = new Vector();
  77.             openMissions.put(skill.getName(), v);
  78.         }
  79.         return v;
  80.     }
  81.     
  82.     /*
  83.     Check if the given mission is in the blackboard.
  84.     */
  85.     public boolean missionIsPosted(Mission mission) {
  86.         Vector v = (Vector)openMissions.get(mission.getSkillName());
  87.         if (v==null) return false;
  88.         else return v.contains(mission);
  89.     }
  90.  
  91.     /*
  92.     An agent is requesting to be removed from a mission, for example, because
  93.     it has found a more important mission to attend to, or because it has died.
  94.     Here we have to make the decision about whether or not to add the mission
  95.     back onto the blackboard. We DO if the mission is still incomplete and is
  96.     not full.
  97.     */
  98.     public void removeFromMission(Agent agent, Mission mission) {
  99.         if (mission==null) return;
  100.         mission.removeMember(agent);
  101.         if (!mission.isFull() && !mission.getMissionComplete()) {
  102.             Vector v = (Vector)openMissions.get(mission.getSkillName());
  103.             if (v==null) {
  104.                 v = new Vector();
  105.                 openMissions.put(mission.getSkillName(), v);
  106.             }
  107.             if (!v.contains(mission)) v.addElement(mission);
  108.         }
  109.     }
  110.  
  111.     /*
  112.     Used by agents wishing to apply for a mission.
  113.     The "Application" class is a convenience class defined in this file which
  114.     keeps track of relevant application data.
  115.     */
  116.     public void applyForMission(Agent agent, Mission mission, double relevance) {
  117.         addApplication(new Application(agent, relevance), mission);
  118.     }
  119.  
  120.     /*
  121.     The tricky bit: we want to keep applications ordered by relevance.
  122.     Relevance is a squishy measure of how good they are for the mission,
  123.     taking into account their skill proficiency and they nearness to the 
  124.     mission location.
  125.         
  126.     All THIS does is add the application to the linked-list mission.applications
  127.     such that at the end all the applications are ordered by relevance.
  128.     */
  129.     private void addApplication(Application newApp, Mission mission) {
  130.         if (mission.applications==null) mission.applications = newApp;
  131.         else {
  132.             if (newApp.relevance > mission.applications.relevance) {
  133.                 newApp.nextApplication = mission.applications;
  134.                 mission.applications = newApp;
  135.             }
  136.             else {
  137.                 Application lastApp = mission.applications;
  138.                 Application curApp = mission.applications.nextApplication;
  139.                 while(curApp!=null) {
  140.                     if (newApp.relevance > curApp.relevance) {
  141.                         lastApp.nextApplication = newApp;
  142.                         newApp.nextApplication = curApp;
  143.                         return;
  144.                     }
  145.                     lastApp = curApp;
  146.                     curApp = curApp.nextApplication;
  147.                 }
  148.                 lastApp.nextApplication = newApp;                    
  149.             }
  150.         }
  151.     }
  152.  
  153.     //-----------------------------UPDATES--------------------------------
  154.  
  155.     /*
  156.     This method performs the ACTUAL arbitration. It goes through each mission
  157.     on the blackboard. For each mission, it looks at the list of applications
  158.     for that mission. It starts granting the applications until the mission is full.
  159.     The rest of the applications on the list it denies.
  160.     */
  161.     void updateMissionAssignments(double time) {
  162.         Iterator iterator = openMissions.values().iterator();
  163.         while(iterator.hasNext()) {
  164.             Vector missions = (Vector)iterator.next();
  165.             for (int c=0; c < missions.size(); c++) {
  166.                 Mission mission = (Mission)missions.get(c);
  167.                 
  168.                 //Remove the mission from the blackboard if it is complete.
  169.                 if (mission.getMissionComplete()) {
  170.                     missions.removeElement(mission);
  171.                     c--;
  172.                     continue;
  173.                 }
  174.                 
  175.                 System.out.println(time + " Blackboard " + team + ": Assigning " + mission + " - priority " + mission.getPriority());
  176.                 
  177.                 //Start granting applications
  178.                 Application curApp = mission.applications;
  179.                 while(curApp!=null && !mission.isFull()) {
  180.                     curApp.agent.grantRequest();
  181.                     System.out.println("Granting mission to " + curApp.agent);
  182.                     mission.addMember(curApp.agent);
  183.                     curApp = curApp.nextApplication;
  184.                 }
  185.                 //Deny the rest.
  186.                 while(curApp!=null) {
  187.                     curApp.agent.denyRequest();
  188.                     curApp = curApp.nextApplication;
  189.                 }
  190.                 //if the mission is now full, we want to remove it from the blackboard, since
  191.                 //the blackboard ONLY contains open missions.
  192.                 if (mission.isFull()) {
  193.                     missions.removeElement(mission);
  194.                     c--;
  195.                 }
  196.                 mission.applications = null;
  197.             }
  198.         }
  199.     }
  200.  
  201.  
  202.     /*
  203.     A convenience class for mission-applications. We use it to store who
  204.     wants what mission, and how relevant they are to the mission. These
  205.     will be stored in a linked list ordered by relevance. Then, given N
  206.     open spots in the mission, we will simply read through the N top spots
  207.     in the list.
  208.     */
  209.     public class Application {
  210.         public Agent agent;
  211.         public double relevance;
  212.         
  213.         public Application nextApplication = null;
  214.         
  215.         public Application(Agent agent, double rel) {
  216.             this.agent = agent;
  217.             this.relevance = rel;
  218.         }
  219.     }    
  220. }
  221.