/** * Model.java * * * Created: Wed Sep 19 09:10:59 2001 * * @author Paul Johnson * @version 5.1 */ import java.util.LinkedList; import java.util.Iterator; import java.util.Collections; //for static methods like shuffle and copy import java.util.HashSet; import swarm.objectbase.Swarm; import swarm.objectbase.SwarmImpl; //Subclass model from this import swarm.Globals; // need to call things like Globals.env.getCurrentTime() import swarm.activity.Schedule; import swarm.activity.ScheduleImpl; // Subclass schedule from this import swarm.Selector; // selectors used to schedule actions import swarm.defobj.Zone; //we use Zone below import swarm.activity.Activity; // Activities get returned by some methods /** * The Model class has methods that build objects and it also tells * them to do things. Please note the use of both Lists and Sets here. * For each student, it creates a set of "contacts" that serves an * important role in the Student class. Note also that when a crime * occurs, a Policeman is created and told to investigate.
*
* Please note I'm not creating a separate generator here anymore. I'm
* just drawing random integers from the Swarm uniformIntRand when I
* need them.
* @author Paul E. Johnson
* @version 1.0 */
public class Model extends SwarmImpl {
/** The initial number of agents
*/
final int N;
/** A linked list container for agents */
LinkedList agentList;
/** A swarm schedule object. We create this "empty" framework
* and then insert actions into it. */
Schedule modelSchedule;
/**
* Creates a new Model
instance.
*
* @param aZone a Zone
value
* @param n an int
value
*/
public Model (Zone aZone,int n){
super (aZone); //run the superclass's constructor
N = n;
}
/**
* Create a List and fill it with N student objects. Then, for each
* student, create a container for contacts, and randomly choose
* agents from the agentList to go into the contact list
Swarm class requires the return type be Object, so we have to change
the return type and add a "return this"
*
* @return an Object
value
*/
public Object buildObjects(){
agentList = new LinkedList();
for (int i = 0; i < N; i++) {
Student aStudent = new Student("student" + i);
agentList.addLast(aStudent);
}
//For each student, I need to create a contact list. I'll use a
//Set to hold the contacts. I want to take three agents from the
//list at random and make them the contacts of a student. So I
//have to iterate over the list of students, and for each one
//select some contacts. I create a HashSet to hold the
//contacts. That way I never get duplicates. I also have to be
//careful not to put the agent itself in its own contact
//collection. Maybe there's an easy java way to do it, I don't
//find it.
for (Iterator index = agentList.iterator(); index.hasNext(); ){
Student aStudent= (Student) index.next();
HashSet contacts = new HashSet();
int nOfContacts = 0;
Student aCandidate = null;
//keep looking until we have 3 contacts
while (nOfContacts < 3) {
// draw a random student:
do {
int anInt;
System.out.println (".");
//Note we replace the old use of random numbers
//anInt = myGenerator.nextInt (N);
//with this new use
anInt = Globals.env.uniformIntRand.getIntegerWithMin$withMax(0,N-1);
aCandidate = (Student) agentList.get(anInt);
System.out.println ("anInt " + anInt + "sayhi");
aCandidate.sayHi ();
} while (aCandidate == aStudent);
// don't add student to own contact list
// so keep drawing candidates if you get one is the same as
// aStudent
// Note: when you add to a set, it returns true if that object
// gets added (was not a duplicate).
if ( contacts.add (aCandidate) == true )
{
nOfContacts++;
}
}
aStudent.setContactList(contacts);
}
return this;
}
/**Tell the agents to sayHi
*/
public void checkAgents(){
System.out.println("First, here we traverse the list in order");
for (Iterator index = agentList.iterator(); index.hasNext(); ){
Student aStudent= (Student) index.next();
aStudent.sayHi();
}
}
/**
* Randomly designate some student as the criminal, give his fingerprint to
* a policeman, and tell the policeman to conduct the investigation.
* The results are announced in a printout to System.out.
* @return an Object
value
*/
public Object checkForCrime(){
System.out.println("\n Crime Check: The current time is " + Globals.env.getCurrentTime());
System.out.println( "Students finished interacting. Now turn the cop loose");
Fingerprint criminalPrint;
int suspect = Globals.env.uniformIntRand.getIntegerWithMin$withMax(0,N-1);
criminalPrint = ((Student) agentList.get(suspect)).getFingerprint();
Policeman theCop = new Policeman(agentList);
Student primeSuspect = theCop.investigateCrime (criminalPrint);
if (primeSuspect == null){
System.out.println ("Policeman says he can't find a suspect");
}
else{
System.out.println ("Policeman found a suspect");
System.out.println ("The suspect's name is " + primeSuspect.getName());
}
return this;
}
/**
* We want to repeatedly process the list of agents. Instead of a
simple for loop, we will use a Swarm schedule setup. This is
a "bare" "empty" schedule, and you add actions to it by giving
a "time", an agent to do the action, and a "selector" that
represents the method to be executed.
The term Selector is from Objective-C. It refers to the
"symbolic handle" (my term) that the compiler has for a
method. For example, we want the agents to run their step
method, so we get a "handle" for it by creating a Selector.
Then when we throw the action onto the schedule, we use the
Selector because the schedule mechanism knows how to handle
that. In order to create Selector objects, we are required to
use Java exception handling mechanisms. That requires a pair,
try {}catch(){}. I don't know much about that, just what
Bruce Eckle's Thinking in Java covers.
This seems like a lot of trouble. A "for loop" is as good in
the simplest case, but not in the complicated case, so we want
to build up power.
* @return an Object
value
*/
public Object buildActions() {
super.buildActions(); //must have generic buildActions run first
modelSchedule = new ScheduleImpl (getZone(),false);
Selector agentStepSel = null;
Selector checkCrimeSel = null;
try{
agentStepSel = new Selector (Class.forName("Student"),"step",false);
} catch (Exception e) {
e.printStackTrace (System.err);
System.exit(1);
}
try {
checkCrimeSel = new Selector (this.getClass(),"checkForCrime",false);
} catch (Exception e) {
e.printStackTrace (System.err);
System.exit(1);
}
// for each of the first 10 periods, let the agents interact. Just
// throw actions onto the schedule at times 0,...,9
// Note I'm using the createActionForEach approach, where Swarm knows
// how to handle a whole list of agents, telling each one to do something.
// If you ever need to write a bigger simulation, there are some speedups
// to be had by using a slightly more sophisticate construction.
for (int i = 0; i < 10; i++) {
modelSchedule.at$createActionForEach$message (i, agentList, agentStepSel);
}
modelSchedule.at$createActionTo$message(11,this,checkCrimeSel);
return this;
}
/**
* Describe activateIn
method here.
*
* @param swarmContext a Swarm
value
* @return an Activity
value
*/
public Activity activateIn (Swarm swarmContext) {
super.activateIn (swarmContext); //need super's activatein() method
modelSchedule.activateIn (this); //modelSchedule gets stepped along with higher level context. This means "time" is meaningful. Note getCurrentTime() elsewhere.
return getActivity ();
}
/**
* A go method is needed because we need to run the activity structure that
* was created in buildActions() and put into the time scheme by activateIn().
* You may see some Swarm models with a graphical interface in which a go
* method need not be explicitly created, and they get away with that by
* using a top level swarm from the GUISwarm class. Here, were are just using
* Swarm, and no GUI controls are available.
* @return an Object
value
*/
public Object go () {
System.out.println
("You typed the right thing. We are now in the go method, and the student Model will run:");
//use the inherited method getActivity(), and tell the
//resulting Activity to run(). Could be more clear to new
//users and write like so:
Activity anActivity = this.getActivity();
anActivity.run();
//getActivity ().run ();
// I've seen other example programs that do it like this:
// getActivity ().getSwarmActivity ().run ();
// I can't tell what getSwarmActivity does here.
// It seems not needed to me.
return getActivity ().getStatus ();
}
}// Model