/* * CEMETERY ORGANIZATION OF ANTS * A MODIFIED VERSION OF DENEUBOURG'S MODEL OF * CEMETERY ORGANIZATION IN ANT SOCIETIES * * The behavior modeled by the model is how ants collect the dead * bodies of their groupmates into clusters. It is a very similar model * to that of breed sorting collect their breed into clusters according * to their age. The only difference here is that for the sake of * simplicity we have not implemented different kinds of items. * * The interesting phenomena here is that while the algorithm coded in * the individual agents is fairly simple and involves no (direct) * communication with the others, the performance of the society results * in a fairly ordered landscape. Note that in the original model the ants * has no information at all from the global level, while in this version * on the contrary they do use the initial density for decision making. * * In this modified version the algorithm performed by the individual * agents is the following: they wander around the space randomly, * performing brownian motion. At each location they decide whether * swapping the item carried by them with the one at the given location * results in better local organization. (If they carry something and * there is nothing at the given location, then swapping means putting * the carried item down, while when they are empty but there is some item * at the location swapping means picking the item up.) * * Written by Tamás Kozsik, 15/06/1998 * English version by László Gulyás, 31/07/1998 * (c) 1998. CEU Systems Laboratory */ @model AntSort { @uses ; // For Gird2d and Discrete2d objects // Model Parameters @var: int Size; // Size of the world @var: float Density; // Density of the items @var: int NumOfAnts; // Number of Ants // Shorthands $define SIZE: "model->Size"; $define Nothing: "0", Something: "1"; // The world @var: Discrete2d space; // An administrative map of the world to be able to esily identify // the ant at the given location @var: Grid2d lookUpTable; // An offset table for adjacent locations // Note the use of the modifier 'static' together with that of 'public' // which will work but result in a warning message in the current version // of MAML. Please, ignore it! $define numOfDirections: "8"; @var static public: [] int dx; @var static public: [] int dy; /////////////////////////////////////////////////////////////////////////// // The definition of the ANT @agent Ant { @var: int x, y; // Current position @var: int carries; // What it carries // Decides whether to swap and does if thinks so. @sub: (void) swap { // If swapping has any meaning (that is the carried item isn't // the same than the one at the current location) if ([model->space getValueAtX: x Y: y] != carries) { int neighbors = 0; int down; int i; // Then count the number of neighbors holding item for (i=0; ispace getValueAtX: (x+SIZE+dx[i])%SIZE Y: (y+SIZE+dy[i])%SIZE] == Something); // If the local density is higher than the global one then // assure that there is an item at this location, otherwise // make it empty down = ( ( (double)neighbors >= 8*model->Density ) ? Something : Nothing); [model->space putValue: down atX: x Y: y]; carries = ( (down==Something) ? Nothing : Something); } } // A step in the brownian motion @sub: (void) brown_move { // Select a random direction int direction = [uniformIntRand getIntegerWithMin: 0L withMax: (numOfDirections-1)]; // Determine the corresponding offsets int new_x = (x+SIZE+dx[direction])%SIZE, new_y = (y+SIZE+dy[direction])%SIZE; // If that location is empty then move there if ([model->lookUpTable getObjectAtX: new_x Y: new_y] == NULL) { [model->lookUpTable putObject: NULL atX: x Y: y]; x = new_x; y = new_y; [model->lookUpTable putObject: self atX: x Y: y]; } } } /////////////////////////////////////////////////////////////////////////// // The schedule of the model @schedule cyclic (2) { // For all ants 0: @forEach groupOfAnt swap; // Swapping 1: @forEach groupOfAnt brown_move; // Moving } /////////////////////////////////////////////////////////////////////////// // Initialization of the model @init: // Creating an initializing the offset table for adjacent locations @create [numOfDirections] int dx; @create [numOfDirections] int dy; dx[0] = -1; dy[0] = -1; dx[1] = -1; dy[1] = 0; dx[2] = -1; dy[2] = 1; dx[3] = 0; dy[3] = -1; dx[4] = 0; dy[4] = 1; dx[5] = 1; dy[5] = -1; dx[6] = 1; dy[6] = 0; dx[7] = 1; dy[7] = 1; // Initializing the space @create Discrete2d space { [space setSizeX: Size Y: Size]; } {// Filling up the space randomly int i, j; for (i=0; icarries = Nothing; // Finding a random location for the ant (which is not // occupied yet) do { h->x = [uniformIntRand getIntegerWithMin: 0L withMax: (Size-1)]; h->y = [uniformIntRand getIntegerWithMin: 0L withMax: (Size-1)]; } while ([lookUpTable getObjectAtX: h->x Y: h->y] != NULL); // Record it in the lookUpTable too [lookUpTable putObject: h atX: h->x Y: h->y]; } } } } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// @observe AntSort { // Variables of the display @var: XColormap colormap; // Colormap @var: ZoomRaster worldRaster; // The window on the screen @var: Value2dDisplay spaceDisplay; // Used to display the items @var: Object2dDisplay antDisplay; // Used to display the ants // The frequency of the observation @var: int displayFrequency; // Probed variables @probe: var "Size", var "Density", var "NumOfAnts", var "displayFrequency"; // Shorthands for Colors $define Nothing_Color: "0", Something_Color: "1", Empty_Ant: "2", Carrier_Ant: "3"; /////////////////////////////////////////////////////////////////////////// // Adding the self-drawing method to the ant @extendAgent Ant { @sub: (void) drawSelf: (Raster) r { [r drawPointX: x Y: y Color: (carries ? Carrier_Ant : Empty_Ant)]; } } /////////////////////////////////////////////////////////////////////////// // The schedule of the observation @schedule cyclic (displayFrequency) { // We only do it at the // given frequency 0: @planDef seq { @to spaceDisplay display; // Displaying the items @to antDisplay display; // Displaying the ants @to worldRaster drawSelf; // Refreshing the whole // stuff on the screen } } /////////////////////////////////////////////////////////////////////////// @init: // Initialization of the probed variables Size = 10; Density = 0.7; NumOfAnts = 10; displayFrequency = 1; // Displaying the probes and stopping the simulation // to let the user alter them @buildProbes; [model probe]; [controlPanel setStateStopped]; // Initialization of the model @initModel; // Creating the objects for the display // Creating the colormap @create XColormap colormap; [colormap setColor: Nothing_Color ToName: "black"]; [colormap setColor: Something_Color ToName: "red"]; [colormap setColor: Empty_Ant ToName: "white"]; [colormap setColor: Carrier_Ant ToName: "green"]; // Creating the display object @create ZoomRaster worldRaster; [worldRaster setColormap: colormap]; [worldRaster setZoomFactor: 4]; [worldRaster setWidth: Size Height: Size]; [worldRaster setWindowTitle: "Ants' World"]; [worldRaster pack]; // Creting the item-displayer @create Value2dDisplay spaceDisplay { [spaceDisplay setDisplayWidget: worldRaster Colormap: colormap]; [spaceDisplay setDiscrete2dToDisplay: space]; } // Creating the ant-displayer @create Object2dDisplay antDisplay { [antDisplay setDisplayWidget: worldRaster]; [antDisplay setDiscrete2dToDisplay: lookUpTable]; [antDisplay setObjectCollection: groupOfAnt]; [antDisplay setDisplayMessage: M(drawSelf:)]; // the drawing method } }