Annotated code for Schelling's segregation model in C: Version schelling2.c

This is a web page with annotations for the code in the file schelling2.c, which is a C program implementing Thomas Schelling's model of segregation from Micromotives and Macrobehavior, according to a Pascal version of that model written by Robert Axelrod. This version of the program is based on the program in schelling.c and please read that page if you haven't already. This annotation only mentions the differences between the two files To download the code for schelling2.c without these remarks please follow this link:

There are three versions of this program, annotations for the other two are the files:


Global declarations

The global declarations for this program are different from schelling.c, since we have made some constants into parameters which can be determined at runtime and added new functions to deal with that.

Note in particular the statements regarding global variables, the arrays and then the new functions get_parameters() and initialize_arrays()

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

/* Schelling's model of segregation. C code by Benedikt Stefansson January 1998
   based on original Pascal code by Tom Belding and Robert Axelrod */

/* Global vars */
int number_of_reports=8;
int events_per_report=100;
int num_white=25;
int num_agents=50;

/* Declare arrays */
static int occupant[64];
static int neighbor_loc[64][8];
static int * color;
static int * location;


/* Declare subroutines */ 
int content(int i);
void random_move(int i);
int get_random_location();
void initial_output();
void initialize_agent_color();
void initialize_agent_location();
void initialize_neighbor_list();
void periodic_output(int event,int moves);
void get_parameters();
void initialize_arrays();

The main function

The main difference between the two main functions in this program and in schelling.c is that here we call get_parameters() and initialize_variables() before starting the simulation.

void main() {
  int i;
  int report;
  int events_in_report;
  int event=0;
  int moves_this_period=0;
  
  /* Get parameter settings */
  get_parameters();

  /* Allocate memory for agent lists */
  initialize_arrays();
  
  /* Initialize lattice and neighborhood list */
  initial_output();
  initialize_agent_color();
  initialize_agent_location();
  initialize_neighbor_list();
  periodic_output(0,0);

  /* Count timesteps or events */
  event = 0;
  i = 0;

  /* Outer event loop */
  for (report=0;report<number_of_reports;report++) {
    /* Count of actual moves */
    moves_this_period = 0;

    /* Inner event loop */
    for (events_in_report = 0;events_in_report < events_per_report;events_in_report++) {
      event++;
      /* Work our way through the agent list */
      if (i >= num_agents)
	i = 0;
      if (!content(i)) {
	/* If agent is not content then move it*/
	moves_this_period++;
	random_move(i);
      }
      i++;
    }
    /* Print out report */
    periodic_output(event,moves_this_period);   
  } 

  exit(0);
}

Changes to function periodic_output()

We have made slight changes to the function periodic_output(), in that the strings used to symbolize the different colors on the board, and an emtpy cell, are now stored in a char array. The changes are to be found in the initialization of the local variables and in the print loop. Compare this to the previous version.

void periodic_output(int event,int moves) {
  /* Prints out periodic state of map */
  int line;
  int address;
  int column;
  char str[3]={'.','@','#'};
    
  if(event==0) 
    printf("Initial state of map\n");
  else
    printf("Event %3d. Moves this period %3d\n",event,moves);  
  
  address=0;
  for(line=0;line<8;line++) {
    for(column=0;column<8;column++) {
      /* Output agent map */
      if(occupant[address]==-1) 
	printf(" . ");
      else 
	printf("%3d",occupant[address]);
      address++;
    }
    /* Rewind and put space between */
    address-=8;
    printf("     ");
    for(column=0;column<8;column++) {
      /* Output color map */
      if(occupant[address]==-1)
	printf(" %c ",str[0]);
      else 
	printf(" %c ",str[color[occupant[address]]+1]);
      address++;
    }
    printf("\n");
  }
  printf("\n");

}

Input of parameters

The program now prints a blurb and then queries the user for several parameters, number of agents, number of white type and the number of reports and events per report.

The input of parameters follows a simple format. We use the variable temp to hold the input, and if temp is not in the proper interval we try again. The variable is thus set to 0 (FALSE) before each query, and the while loop will continue to be executed until a correct value is input. Then the temp value is passed to the corresponding parameter.

void get_parameters() {
  /* Read in several parameters before running sim */
  int temp=0;

  printf("Schelling's segregation model\n");
  printf("code by Benedikt Stefansson\n");
  printf("based on Pascal program by\n");
  printf("Robert Axelrod and Ted Belding\n");

  while(!temp) {
    printf("Input number of agents (0-64): ");
    scanf("%d",&temp);
    if(temp<=0 || temp>=64) {
      printf("Number of agents must be between 0-64\n");
      temp=0;
    } else {
      num_agents=temp;
    }
  }
  temp=0;
  
  while(!temp) {
    printf("Number of white agents (1-%d): ",num_agents-1);
    scanf("%d",&temp);
    if(temp<=0 || temp>=num_agents) {
      printf("Number of white agents must be between 1-%d\n",num_agents);
      temp=0;
    } else {
      num_white=temp;
    }
  }
  temp=0;
  
  while(!temp) {
    printf("Number of reports to print: ");
    scanf("%d",&temp);
    if(temp<=0) {
      printf("Number of reports must be positive\n");
      temp=0;
    } else {
      number_of_reports=temp;
    }
  }
  temp=0;
  
  while(!temp) {
    printf("Number of events per report: ");
    scanf("%d",&temp);
    if(temp<=0) {
      printf("Number of events must be positive\n");
      temp=0;
    } else {
      events_per_report=temp;
    }
  }

}

Dynamic allocation of arrays

Since the user is free to choose the number of agents at runtime, we now dynamically allocate the color and location arrays. The library calloc() is used and the address of the first element of the resulting arrays is stored in the pointers color and location respectively.

void initialize_arrays() {
  /* Allocate memory for the color and location arrays */
  color=calloc(num_agents,sizeof(int));
  location=calloc(num_agents,sizeof(int));

}

Written by Benedikt Stefansson: benedikt@ucla.edu
Last modified: Mon Feb 2 12:14:06 PST 1998