8-001 // Sugarscape in Swarm. Copyright © 1997 Nelson Minar
8-002 // This program is distributed without any warranty; without even the
8-003 // implied warranty of merchantability or fitness for a particular purpose.
8-004 // See file LICENSE for details and terms of copying.
8-005 
8-006 #import "ModelSwarm.h"
8-007 //#import <objectbase.h>
8-008 #import <random.h>  //uniformUnsRand uniformIntRand
8-009 
8-010 #include <misc.h> // strdup
8-011 @implementation ModelSwarm
8-012 
8-013 // Code to create the model swarm parameter set.
8-014 // Note that we don't make probes for all the variables - some variables,
8-015 // like world size, aren't likely to be modified.
8-016 + createBegin: aZone
8-017 {
8-018   ModelSwarm *obj;
8-019   id <ProbeMap> probeMap;
8-020 
8-021   obj = [super createBegin: aZone];
8-022 
8-023   // Parameters for the simulation
8-024   obj->numAgents = 400;
8-025   obj->alpha = 1;
8-026   obj->replacement = 0;
8-027   obj->maxVision = 6;
8-028   obj->maxMetabolism = 4;
8-029   obj->minInitialSugar = 5;
8-030   obj->maxInitialSugar = 25;
8-031   obj->deathAgeMin = 99998;
8-032   obj->deathAgeMax = 100000;
8-033   obj->worldXSize = 50;
8-034   obj->worldYSize = 50;
8-035   obj->datafile = strdup("sugarspace.pgm");
8-036 
8-037 
8-038   // The creation of a probe map - these parameters are the ones that
8-039   // are easy to modify in the GUI.
8-040   probeMap = [EmptyProbeMap createBegin: aZone];
8-041   [probeMap setProbedClass: [self class]];
8-042   probeMap = [probeMap createEnd];
8-043 
8-044   [probeMap addProbe: [probeLibrary getProbeForVariable: "numAgents"
8-045 				    inClass: [self class]]];
8-046   [probeMap addProbe: [probeLibrary getProbeForVariable: "alpha"
8-047 				    inClass: [self class]]];
8-048   [probeMap addProbe: [probeLibrary getProbeForVariable: "replacement"
8-049 				    inClass: [self class]]];
8-050   [probeMap addProbe: [probeLibrary getProbeForVariable: "maxMetabolism"
8-051 				    inClass: [self class]]];
8-052   [probeMap addProbe: [probeLibrary getProbeForVariable: "maxVision"
8-053 				    inClass: [self class]]];
8-054   [probeMap addProbe: [probeLibrary getProbeForVariable: "minInitialSugar"
8-055 				    inClass: [self class]]];
8-056   [probeMap addProbe: [probeLibrary getProbeForVariable: "maxInitialSugar"
8-057 				    inClass: [self class]]];
8-058   [probeMap addProbe: [probeLibrary getProbeForVariable: "deathAgeMin"
8-059 				    inClass: [self class]]];
8-060   [probeMap addProbe: [probeLibrary getProbeForVariable: "deathAgeMax"
8-061 				    inClass: [self class]]];
8-062   [probeMap addProbe: [probeLibrary getProbeForVariable: "datafile"
8-063 				    inClass: [self class]]];
8-064   [probeMap addProbe: [probeLibrary getProbeForMessage: "addNewRandomAgent"
8-065 				    inClass: [self class]]];
8-066 
8-067   [probeLibrary setProbeMap: probeMap For: [self class]];
8-068   
8-069   return obj;
8-070 }
8-071 
8-072 // Build objects is the code where the model swarm creates all the
8-073 // agents and other objects in the simulation model.
8-074 - buildObjects
8-075 {
8-076   int i;
8-077   
8-078   [super buildObjects];
8-079 
8-080   // First, set up the object that is the sugarspace - the environment.
8-081   sugarSpace = [SugarSpace createBegin: self];
8-082   [sugarSpace setSizeX: worldXSize Y: worldYSize];
8-083   [sugarSpace setMaxSugarDataFile: datafile];
8-084   sugarSpace = [sugarSpace createEnd];
8-085   [sugarSpace setSugarGrowRate: alpha];
8-086 
8-087   // create a list to store all the agents
8-088   agentList = [List create: self];
8-089 
8-090   // And create a bunch of agents to live in the world.
8-091   for (i = 0; i < numAgents; i++)
8-092     [self addNewRandomAgent];
8-093 
8-094   // Create a "reaper queue" to manage agent deaths
8-095   reaperQueue = [List create: self];
8-096 
8-097   // And create a suffler object to randomize agent order
8-098   shuffler = [ListShuffler createBegin: self];
8-099   [shuffler setUniformRandom: uniformUnsRand];
8-100   shuffler = [shuffler createEnd];
8-101   
8-102   return self;
8-103 }
8-104 
8-105 // Now it's time to create the schedule.
8-106 - buildActions
8-107 {
8-108 
8-109   id modelActions;  // holds together a sequence of actions for each timestep
8-110   [super buildActions];
8-111 
8-112   // One time tick, a set of several actions:
8-113   //   randomize the order of agent updates (to be fair)
8-114   //   update all the agents
8-115   //   kill off the agents who just died
8-116   //   update the sugar on the world
8-117   modelActions = [ActionGroup create: self];
8-118   [modelActions createActionTo: sugarSpace message: M(updateSugar)];
8-119   [modelActions createActionTo: shuffler message: M(shuffleWholeList:) : agentList];
8-120   [modelActions createActionForEach: agentList message: M(step)];
8-121   [modelActions createActionTo: self message: M(reapAgents)];
8-122 
8-123   // The schedule is just running our actions over and over again
8-124   modelSchedule = [Schedule createBegin: self];
8-125   [modelSchedule setRepeatInterval: 1];
8-126   modelSchedule = [modelSchedule createEnd];
8-127   [modelSchedule at: 0 createAction: modelActions];
8-128 
8-129   return self;
8-130 }
8-131 
8-132 // Create a new agent at random and put it in the world.
8-133 - addNewRandomAgent
8-134 {
8-135   int x, y;
8-136   SugarAgent *agent;
8-137 
8-138   // turn off these warnings.
8-139   [[sugarSpace getAgentGrid] setOverwriteWarnings: 0];
8-140 
8-141   // Create the agent object
8-142   agent = [SugarAgent createBegin: self];
8-143   [agent setModelSwarm: self];
8-144   agent = [agent createEnd];
8-145 
8-146   // Give the agent a random initial position and parameters.
8-147   //pj 20040725: should be -1 to "keep in bounds"
8-148   x = [uniformIntRand getIntegerWithMin: 0 withMax: [sugarSpace getSizeX]-1];
8-149   y = [uniformIntRand getIntegerWithMin: 0 withMax: [sugarSpace getSizeY]-1];
8-150   [sugarSpace addAgent: agent atX: x Y: y];
8-151   [agent setCurrentSugar: 
8-152 	   [uniformIntRand getIntegerWithMin: minInitialSugar
8-153 			   withMax: maxInitialSugar]];
8-154   [agent setMetabolism:
8-155 	   [uniformIntRand getIntegerWithMin: 1 withMax: maxMetabolism]];
8-156   [agent setVision: 
8-157 	   [uniformIntRand getIntegerWithMin: 1 withMax: maxVision]];
8-158   [agent setDeathAge:
8-159 	   [uniformIntRand getIntegerWithMin: deathAgeMin
8-160 			   withMax: deathAgeMax]];
8-161   
8-162   [self agentBirth: agent];
8-163 
8-164   // turn the warnings back on
8-165   [[sugarSpace getAgentGrid] setOverwriteWarnings: 1];
8-166   return self;
8-167 }
8-168 
8-169 // Methods to handle the birth and death of agents
8-170 - agentBirth: (SugarAgent *)agent
8-171 {
8-172   [agentList addLast: agent];
8-173   return self;
8-174 }
8-175 
8-176 - agentDeath: (SugarAgent *)agent
8-177 {
8-178   [reaperQueue addLast: agent];
8-179   if (replacement)				  // Replacement rule R (p.32)
8-180     [self addNewRandomAgent];
8-181   return self;
8-182 }
8-183 
8-184 // remove all the agents on the reaperQueue from the agentList
8-185 // This allows us to defer the death of an agent until it's safe to
8-186 // remove it from the list.
8-187 - reapAgents
8-188 {
8-189   id index, agent;
8-190   
8-191   index = [reaperQueue begin: self];
8-192   while ((agent = [index next]))
8-193     {
8-194       [agentList remove: agent];
8-195       [agent drop];
8-196     }
8-197   [reaperQueue removeAll];
8-198   return self;
8-199 }
8-200 
8-201 // A technical detail of scheduling
8-202 - activateIn: swarmContext
8-203 {
8-204   [super activateIn: swarmContext];
8-205   [modelSchedule activateIn: self];
8-206   return [self getActivity];
8-207 }
8-208 
8-209 // accessor methods
8-210 - (SugarSpace *)getSugarSpace
8-211 {
8-212   return sugarSpace;
8-213 }
8-214 
8-215 - getAgentList
8-216 {
8-217   return agentList;
8-218 }
8-219 
8-220 @end
