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 8-008 #import //uniformUnsRand uniformIntRand 8-009 8-010 #include // 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; 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