/* * * MAML TUTORIAL (Model 4.2) -- The file describing the agents' behavior * For full description refer to * http://www.syslab.ceu.hu/maml/tutorial/ * * 'Segregation' a model by Thomas Schelling * * This simulation is based on a model published by T. Schelling, and consists * of agents living in a 2d grid. The agents are of two colors (blue and red) * and stay at a given location only if the ratio of the number of their * neighbors the same color and the number of neighbors is more than a * specified limit. What is interesting is that if this limit is fairly low * (appr. 0.5), this fairly tolerant behaviour leads to surprisingly high * rate of segregation at the global level. * It was implemented in MAML v0.03 as part of its tutorial. * * (c) 1998, CEU Systems Laboratory * */ @agent Resident { @uses ; // We need this Swarm package // as we are using lists here // The agent's state variables: // color -- its color // age -- its current age // maxAge -- its age at death // posX, posY -- its current location on the grid // limit -- the ratio of neighbors with different color // it can stand @var: int color, age, maxAge; @var: int posX, posY; @var: float limit; // Setting the location of the agent @sub: (void) setX: (int) x Y: (int) y { posX = x; posY = y; // It should be recorded on the global grid too [model->city putObject: self atX: posX Y: posY]; } // Setting the agent's parameters @sub: (void) setColor: (int) c maxAge: (int) a AndLimit: (float) l { color = c; age = 0; maxAge = a; limit = l; } // Making a step @sub: (void) step { // Temporary variables (conting of the neighbors) int i, j, num, numOfOK, numOfEmpties; // The current ratio float level; Resident *dummy; // The neighbor under observation id emptyX, emptyY; // List of possible locations to go // (X and Y coordinates separately). // Creating the two empty lists emptyX = [List create: [self getZone]]; emptyY = [List create: [self getZone]]; // Doing the statistics num = numOfOK = 0; for (i=-1; i<2; i++) for(j=-1; j<2; j++) { // If the location is not ours if ((i!=0) || (j!=0)) { // Get the agent at the location dummy = [model->city getObjectAtX: ((posX+i+model->citySize) % model->citySize) Y: ((posY+j+model->citySize) % model->citySize)]; // If the location wasn't empty make the statistics if (dummy != nil) { num++; if (dummy->color == color) numOfOK++; } else { // otherwise do the statistics of emptyIsOK if (model->emptyIsOK) { numOfOK++; num++; } // And append the location to the 'emptyLoc' list [emptyX addFirst: (id) ((posX+i+model->citySize) % model->citySize)]; [emptyY addFirst: (id) ((posY+j+model->citySize) % model->citySize)]; } } } // Calculating the current ratio level = (float) numOfOK / (float) num; numOfEmpties = [emptyX getCount]; // If we have to move and there is place to move to, let's move if ((level < limit) && (numOfEmpties > 0) ) { // If there is only 1 place, then we set it frankly if (numOfEmpties == 1) i = 0; else // otherwise we select randomly i = [uniformIntRand getIntegerWithMin: 0 withMax: (numOfEmpties-1)]; // Clear the current location, and set the new one [model->city putObject: nil atX: posX Y: posY]; [self setX: (int) [emptyX atOffset: i] Y: (int) [emptyY atOffset: i] ]; } // Clear the lists [emptyX removeAll]; [emptyY removeAll]; [emptyX drop]; [emptyY drop]; // Increment the age age++; // If its time to die, then do so. // (That is, create a new resident at a random location). if (age > maxAge) { [model->city putObject: nil atX: posX Y: posY]; [model createNewResident: self]; } } }