The schedules described so far are of a particular static sort. Each agent, or each agent in a list, is told to execute some action at some particular time. What if the simulation is designed so that the activation of a certain agent is conditional on events within the model? The need to create a flexible schedule gives rise to an important feature of Swarm that is referred to as a dynamic schedule. The Mousetrap application is a fully worked out example that shows the power of dynamic scheduling.
The idea behind dynamic scheduling is so simple that one can be in danger of confusing it by explaining it too much. Simply put, the strategy is as follows. First, create an object from the Swarm Schedule class. Don't put any actions in the schedule, just let it sit there in the buildActions method, doing nothing (yet). Second, write a method that tells that schedule to add things that are to be executed at particular times. It is as simple as that.
The concept is quite simple, but, as the Mousetrap application illustrates, it can be quite complicated in the implementation. The simplest possible dynamic scheduling project of which we are aware was made available in the package Swarmfest99-demos (in the swarm ftp site, it should be available in the users-contrib/anarchy section). The application is called simpleObserverBug-growth. It begins with the familiar exercise from the Swarm tutorial and then models the regeneration of the food supply.
In the simpleObserverBug-growth example, the ModelSwarm.m file has all of the usual ingredients. The dynamic schedule is created in the buildActions method, like so:
growthSchedule = [Schedule createBegin: self]; [growthSchedule setAutoDrop: 1]; growthSchedule = [growthSchedule createEnd]; |
The growthSchedule is created and the setAutoDrop feature is set, so that actions are executed one time and then dropped from the growthSchedule. Otherwise, once we add an action into the schedule, it will repeat itself forever.
In the ModelSwarm.m, one also finds the method that has the power to add items to the schedule. It is called scheduleGrowthAtX:Y:. When this method is called, it grows more food at a particular spot.
- scheduleGrowthAtX: (int)x Y: (int)y { long time; time=[[self getActivity] getCurrentTime]; [growthSchedule at: time+growthInterval createActionTo: foodSpace message: M(putValue:atX:Y:):1:x:y]; return self; } |
As you can see, this method retrieves the current time, and then it tells the growth schedule to create an action to the foodspace at a time in the future. And the ungainly M() notation appears, which we described in greater detail in Section 9.2. Note that the putValue:atX:Y: method requires 3 integer parameters, which represent the value being put in the space and the two coordinates.
The preceeding steps are the essence of creating the dynamic schedule. The empty schedule is created, and a method is created that can tell that schedule to add an item. The only remaining step is to design the simulation so that this method actually gets executed during the course of the program. That means that some class has to have a method that can tell the modelSwarm to execute its scheduleGrowthAtX:Y: method. In this example, it is done by making the foodSpace object aware of the modelSwarm and the, when a piece of food is consumed, the dynamic scheduling process is put to use. From the FoodSpace.m class, here is the relevant method:
- eatX: (int)x Y: (int)y { [self putValue: 0 atX: x Y: y]; [model scheduleGrowthAtX: x Y: y]; return self; } |