Complexity of Cooperation Web Site

Full Cultural Model


program Culture;


{Robert Axelrod, School of Public Policy, U Michigan, Ann Arbor, MI 48109}
{   This version is based on version 2.6 Axelrod's Org program for his Cultural Model.}

    const
        Version = 2.6;                                      {Program Version Number}
        test = true;                        {if test=true, no run_number  is read or written.}
                                        {Run # is set to 0 for test=true runs}
        old_random_seed = 0;        {0 means new seed, else enter an old seed to reuse}
        cyclemax_float = 10;            {# cycles in each reporting period.  Cylce is one active actor, ie event. eg 1000}
        periodmax = 10;             {number of periods of cyclemax each.Max 30,000 }
        mapmax = 1;                     {number of maps}
        popmax = 1;                 {number of replications of each map, each with cyclemax*periodmax active actors}
        mutuation_rate_perpop_percycle = 0.0;       {mutation rate, per pop, per cycle for drift, eg 0.0}
        broadcast_rate_per_10000_cycles = 0;    {cylces in 10,000 that are interactions with broadcaster, not neighbors}
{                                               e.g. 200 means 2% of cycles are from broadcast, 98% from a neighbor}
        flat_map = true;                {true is old method of no wrap around. false is torus}

{production parameters}
        N_Xmax = 1;             {Map sizes used. (max 5. See Initialize_Run, and def production_array)}
        Xmax_tops = 50;         {   largest allowable value of Xmax1, Xmax2, etc.}
        Ymax_tops = Xmax_tops;  {assume square map}
        Xmax1 = 10;             {   first map size East to West:    Square map assumed. Max is Xmax_tops}
        Xmax2 = 5;              {   second map size, etc.}
        Xmax3 = 7;
        Xmax4 = 12;
        Xmax5 = 17;

        N_interaction_types = 1; {neighborhood types used}
        Interaction_types_tops = 16;{  largerst allowable is 16}
        Interaction_Types1 = 4; {first used. : 4=NEWS, 8=3x3, 12=diamond, 16=diamond+NEWS repeated}
        Interaction_Types2 = 8;
        Interaction_Types3 = 12;
        Interaction_Types4 = 0;
        Interaction_Types5 = 0;

        N_bitmax = 1;       {Chromosome sizes used (max 5)}
        bitmax_tops = 15;       {       largest allowable bitmax1, bitmax2, etc}
        bitmax1 = 5;                {   Size of chromosome in first set of pops, ie bits in indiv's culture. Max bitmax_tops}
        bitmax2 = 10;           {   second string length, etc.}
        bitmax3 = 15;
        bitmax4 = 0;
        bitmax5 = 0;

        N_allelemax = 1;        {Alleles in indiv's culture  (number of different values to be used) (max 5)}
        allelemax1 = 15;            {Alleles in each gene in first set of pops}
        allelemax2 = 10;        {Alleles in each gene in first set of pops}
        allelemax3 = 15;
        allelemax4 = 0;
        allelemax5 = 0;

{reporting options: }
        TextGridReport = false;         {Report period grid data to text window; slows things down}
        Graphics = false;                   {Show graphics in drawing window if true}
        Graph_distance = false;         {Plot  cul. distance in drawing window if true (and graphics=true)}
        WritePeriodicStats = true;  {Writes period statistics to period_output if true}
        WriteRegionStats = false;       {Writes data on regions each period, huge unless few periods}
        WriteRegionStatsAtEnd = true;   {Writes data on regions at end of a case to Region_Output if neighbor_clear}
        stack_map = true;               {if false, can see multiple maps in drawing window}
        report_bit_origin = false;      {write origin of first bit as Xmax*(y-1)+x-1}

{graphics view: }
        w = 10;                     {Graphics constant: width of a cell, eg 20}
        h_offset = 20;              {Graphics constant: where grid starts in drawing window, horizontal offset, eg 20}
        v_offset = 20;              {Graphics constant: where grid starts, eg 20}
        pen_size = 4;               {Graphics constant: height and width of pen, eg 6}

{compiler constants}
        Xmax_topsPlus1 = Xmax_tops + 1;         {highest values allowed of Xmax}
        Ymax_topsPlus1 = Ymax_tops + 1;
        XmaxYmax_tops = Xmax_tops * Ymax_tops;
        Run_Number_File_Name = 'Run Number File';

    type
        x_type = 1..xmax_tops;              {range of indiv's x coord}
        y_type = 1..ymax_tops;              {range of indiv's y coord}
        bit_type = 1..bitmax_tops;          {bit on culture}
        culture_array = array[0..Xmax_topsPlus1, 0..Ymax_topsPlus1, 1..bitmax_tops] of integer;  {for x, y,bit: max sizes allowed}
        culture_array_pointer = ^culture_array;
        Culture_Array_Handle = ^culture_array_pointer;
        done_array = array[0..Xmax_topsPlus1, 0..Ymax_topsPlus1] of boolean;{for analyzing regions. max actual geo }
        done_array_pointer = ^done_array;
        done_array_handle = ^done_array_pointer;
        direction_type = 1..16;                         {neighbors: see pop initialization. Starts with north, e, w, s order}
        direction_array = array[1..16] of integer;                  {for x and y moves}
        distance_array = array[1..Xmax_tops, 1..Ymax_tops] of integer;  {for distances right and down}
        distance_array_pointer = ^distance_array;
        distance_array_handle = ^distance_array_pointer;
        production_array = array[1..5] of integer;      {for storing production values}
        location_array = array[1..XmaxYmax_tops] of integer;        {for x and y loc of first member of a region}
        location_array_pointer = ^location_array;
        location_array_handle = ^location_array_pointer;

    var
        initial_datetime, end_datetime: datetimerec;    {date, etc.}
        initial_hour, end_hour: longint;
        start_time, end_time, duration: longint;    {for calc of run's duration}
        random_seed: integer;

        run_number: integer;
        datafile: text;                                     {input data}
        final_output: text;
        region_output: text;
        period_output: text;

        pop: integer;                                       {current population number, 1...popmax}
        period: longint;                                    {current period number, 1..periodmax}

        ix, iy: integer;                                    {x,y coordinate of current active individual}
        jx: integer;                                    {x coord of a neighbor, 0..xmax+1}
        jy: integer;                                    {y coord of a neighbor, 0..ymax+1}
        culture: Culture_Array_Handle;                      {culture of ix,iy,bit - an integer variable}
            {-1 for beyond bord, or 1...  allelemax}
            {x=0 is beyond internal left border, x=xmax+1 is beyond right border, etc.}
            {This allows indivs on internal border to get automatic non-matches with illegal neighbors}
        xmove, ymove: direction_array;              {jointly defines North, East, West, South direction}
        bit: integer;                                       {the current bit of the culture}
        neighbor: direction_type;                       {neighbor, 1 to 16}
        direction: direction_type;                      {16 neighbors; starts with north, s, e, w order, then NE etc.}
        NoMatchPeriodCount: integer;                    {count of no matches in this period}
        NoMatchPopCount: integer;                       {count of no matches in this pop}
        match: boolean;                                 {true if active matches selected neighbor on selected bit}
        bit_distance_sum: longint;                  {sum (in current cycle) of neighbors' bit distances over pop in a pop, }
        n_zero_distance: integer;                       {num (in current cycle) of boundaries of zero bit distance}
        talk_count: integer;                                {counts number of interactions tried in this cycle}
        r_dis: distance_array_handle;                           {bit distance of an actor to its right neighbor}
        d_dis: distance_array_handle;                           {bit distance of an actor to its down neighbor}
        iq: integer;                                            {index of ready queue in analyze regions}
        done: done_array_handle;                        {true if the actor has been processed by regional analysis}
        regions: integer;                                   {count of number of regions}
        region_size: integer;                           {number actors in current region}
        x_region, y_region: location_array_handle;  {x and y loc of first member of a region }
        Xmax: 1..xmax_tops;                         {size of map east to west}
        Ymax: 1..ymax_tops;                         {size of map north to south}
        interaction_types: 1..Interaction_types_tops;   {neighborhood type: 4=NEWS, 8=3x3, 12=diamond, 16=diamond+NEWS repeated}
        bitmax: 1..bitmax_tops;                     {number of genes in culture string}
        allelemax: integer;                             {number of alleles in each gene}
        Xmax_value: production_array;               {Xmax's first, second, third, etc values}
        Interaction_Types_value: production_array;      {interaction_type first, second, third etc values}
        bitmax_value: production_array;         {bitmax's first, second, third, etc values}
        allelemax_value: production_array;      {allelemax's first, second, third, etc values}
        XMaxPlus1: integer;                             {current value of xmax+1}
        YMaxPlus1: integer;                             {current value of ymax+1}
        Xmax_index: x_type;                                     {in main program's loop}
        bitmax_index: bit_type;
        allelemax_index: integer;
        XmaxYmax: integer;                              {current value}
        interaction_types_index: integer;
        case_number: integer;                           {sequential count of pops}
        broadcast_allowed: boolean;                 {true if broadcast_rate_per_10000_cycles > 0}
        broadcast_cutoff_number: integer;           {to get correct prob that an interaction is from a broadcast}
        broadcast_count: longint;                       {number of braodcasts}
        Last_X_Boundary: x_type;                        {for distances. =xmax-1 if flat_world=true, else =xmax}
        Last_Y_Boundary: x_type;                        {for distances. =ymax-1 if flat_world=true, else =ymax}
        map: integer;                                       {2=second map used in this set, etc., goes 1 to mapmax}
        old_seed: integer;                                  {for repitition of maps}
        map_seed: array[1..mapmax] of integer;  {seeds to start maps}
        interaction_seed: array[1..popmax] of integer;  {seeds to start interactions}
        map_x_offset: integer;                          {to displace maps horiztonally, one row for each initial map}
        map_y_offset: integer;                          {to displace maps vertically, one col for each pop type}
        origin_first_bit: distance_array_handle;    {original site of first bit}
        Changes_This_Period: longint;               {count of actual number of cultural changes this period}
        Zones: integer;                                 {count of number of zones, ie domains separated by maximal cul boundary}
        cyclemax: longint;                              {number of cycles in a period, from cyclemax_float input constant}
{wp: WindowPtr; }
                                {pointer to my window for drawing, from Org25, discared in Org26}
 { ---------------------------------------------------------------  }
    function random_one_to_n (n: longint): longint;
                            {proc returns a random number between 1 and n; modified from Bennett's random_range}
        var
            ub, lb: integer;
            r: integer;
    begin                                                       {random gives # betw -32768 and 32767}
        ub := 32767 - (32767 mod n);
        lb := -32768 - (-32768 mod n);                  {truncate distrib on 2 ends so that later mod is OK}
        repeat
            r := random;
        until (r <= ub) and (r >= lb);                      {make sure random genrated is in truncated (even) distrib}
        random_one_to_n := abs(r mod n) + 1;
    end;            {random function}

 { ---------------------------------------------------------------  }
    function Random0or1: integer;
            { returns 0 or 1 with equal probability}
    begin
        if random < 0 then                      {random gives # betw -32768 and 32767}
            Random0or1 := 0
        else
            Random0or1 := 1;
    end;  {Random0or1 fcn}
 { ---------------------------------------------------------------  }

    function ipoisn (mean: real): integer;
            {returns a random integer from a Poisson distribution.}
            {The mean of the distribution is passed into the function. }
            {   Adapted from S. Forrest, GA Program v3., 6/6/83, p8}
            {       Lamda not inputted since always calculated in this fcn}
        var
            k: integer;             {k term in Poisson disribution}
            cum,                        {current value of probability density fcn}
            term,                       {current value of prob distibu? fcn}
            lambda_term,            {cacl to be exp(-mean)}
            tempnum: real;          {random number beteween 0 and 1 from uniform distibution}
    begin
        if mean < 0 then
            write(' Error from ipoisn fcn, mean must be non-negative')
        else
            begin
                lambda_term := exp(-1 * mean);
                tempnum := (random + 32768) / 65635;            {random gives # betw -32768 and 32767}
                                                                            {tempnum gives uniform between 0 and 1 }
        {Here, the cum density fcn for successive values of k is computed. When the cdf}
        {becomes greater than the random variable, tempnum, we quit.  Since k must be}
        {non-negative and since prob(k=0) = lambda_term, k will start out at 0 with}
        {the other values initialized acordingly.}
                k := 0;
                term := lambda_term;
                cum := lambda_term;
                while (cum <= tempnum) and (term > 0.0000005) do {cutoff for high end of distribution}
                    begin
                        k := succ(k);
                        term := (term * mean) / k;
                        cum := cum + term;
                    end;{cylce of cumulation}
                ipoisn := k;                                            {return k as the random number}
            end; {else}
{writeln('ipoisn test: mean, output k ', mean : 8 : 3, k : 3);}
    end;  {ipoisn fcn}
 { ---------------------------------------------------------------  }
    procedure create_graphics_window;
        const
            size = 10;      {font}
        var
            style: integer;
            wrect: rect;
    begin
        wrect.left := 0;
        wrect.top := 40;
        wrect.right := 500;
        if h_offset + xmax_tops * w > 450 then
            wrect.right := h_offset + xmax_tops * w + 50;
        if Graph_distance then
            wrect.bottom := v_offset + (ymax_tops * w + 10) * popmax + 150 + periodmax
        else
            wrect.bottom := v_offset + (ymax_tops * w + 10) * popmax + 100;
        setdrawingrect(wrect);                  {discarded in Org25, restored in Org26}
        showdrawing;
{following from Org25, dicarded inOrg26}
{wp := NewWindow(nil, wrect, 'Map Window', true, 0, WindowPtr(-1), true, 0);}
{setport(wp);}
        TextSize(size);
        getfnum('Courier', style);
        textfont(style);
    end;
 { ---------------------------------------------------------------  }
    procedure initialize_graphics_window;
    begin
        moveto(h_offset, 10);
        if test then
            drawstring(concat(' Ax Org Program, version ', stringof(version : 3 : 2)))
        else
            drawstring(concat(' Ax Org Program, version ', stringof(version : 3 : 2), ', Run', stringof(run_number : 4), '.'));
        moveto(h_offset, 20);
        drawstring(concat('   This run begun on ', stringof(initial_datetime.month : 2), '/', stringof(initial_datetime.day : 2), '/', stringof(initial_datetime.year : 4), ' at ', stringof(initial_datetime.hour : 2), ':', stringof(initial_datetime.minute : 2), '.'));
    end;
 { ---------------------------------------------------------------  }
    procedure frame_rectangle;              {for outline of map}
    begin
        pensize(1, 1);
        penNormal;
        framerect(v_offset + 29 + pen_size + map_y_offset, h_offset - 1 + map_x_offset, ymax * w + v_offset + 31 + map_y_offset, xmax * w - pen_size + h_offset + 1 + map_x_offset);
        pensize(pen_size, pen_size);
    end;
 { ---------------------------------------------------------------  }
    procedure write_run_info;
    begin
        rewrite(final_output, 'Final_Output');          {open output of final file for writing to Excel}
        rewrite(region_output, 'Region_Output');            {open output of region data for writing to Excel}
        if WritePeriodicStats then
            rewrite(period_output, 'Period_Output ');           {open output of period data}
        gettime(initial_datetime);
        initial_hour := initial_datetime.hour;              {to force long int}
        start_time := 60 * 60 * initial_hour + 60 * initial_datetime.minute + initial_datetime.second;
        Writeln('Output of Axelrod''s Org Program, Version ', Version : 5 : 2);
        Write('   This run begun on ', initial_datetime.month : 2, '/', initial_datetime.day : 2);
        Writeln('/', initial_datetime.year : 4, ' at ', initial_datetime.hour : 2, ':', initial_datetime.minute : 2, '.');
        Writeln(cyclemax : 5, ' cycles in each reporting period');
        Writeln(periodmax : 5, '    maximum number of periods in each pop');
        Writeln(mapmax : 5, ' number of maps');
        Writeln(popmax : 5, '   number of pops for each map');
        Writeln(broadcast_rate_per_10000_cycles : 5, '  broadcast rate per 10,000 cycles');
        Writeln(flat_map : 5, ' flat map. True means no wrap around, false means torus map');
{    writeln(Interaction_Types : 5, ' interaction types . 4 means 4 neighbors , etc . See documentation . ');}
        Writeln(mutuation_rate_perpop_percycle : 7 : 3, '   mutation rate, per pop, per cycle');
        Writeln(final_output, 'Output of Axelrod''s Org Program, Version ', Version : 5 : 2);
        Write(final_output, '   This run begun on ', initial_datetime.month : 2, '/', initial_datetime.day : 2);
        Writeln(final_output, '/', initial_datetime.year : 4, ' at ', initial_datetime.hour : 2, ':', initial_datetime.minute : 2, '.');
        Writeln(final_output, cyclemax : 5, '   cycles in each reporting period');
        Writeln(final_output, periodmax : 5, '   maximum number of periods in each pop');
        Writeln(final_output, mapmax : 5, ' number of maps');
        Writeln(final_output, popmax : 5, ' number of pops for each map');
        Writeln(final_output, broadcast_rate_per_10000_cycles : 5, '    broadcast rate per 10,000 cycles');
        Writeln(final_output, flat_map : 5, '   flat map. True means no wrap around, false means torus map');
{    writeln(Interaction_Types : 5, '   interaction types. 4 means 4 neighbors, etc. See documentation.');}
        Writeln(final_output, mutuation_rate_perpop_percycle : 7 : 3, ' mutation rate, per pop, per cycle');
        Writeln(region_output, 'Region Output of Axelrod''s Org Program, Version ', Version : 5 : 2);
        Write(region_output, '   This run begun on ', initial_datetime.month : 2, '/', initial_datetime.day : 2);
        Writeln(region_output, '/', initial_datetime.year : 4, ' at ', initial_datetime.hour : 2, ':', initial_datetime.minute : 2, '.');
        Writeln(period_output, 'Period Output of Axelrod''s Org Program, Version ', Version : 5 : 2);
        Write(period_output, '   This run begun on ', initial_datetime.month : 2, '/', initial_datetime.day : 2);
        Writeln(period_output, '/', initial_datetime.year : 4, ' at ', initial_datetime.hour : 2, ':', initial_datetime.minute : 2, '.');
        if old_random_seed = 0 then
            begin                                                   {generate new seed}
                random_seed := initial_datetime.hour + initial_datetime.minute + initial_datetime.second + (initial_datetime.second * 300) + (initial_datetime.minute * initial_datetime.hour) + (initial_datetime.minute * initial_datetime.second);
                randseed := random_seed;
                Writeln(' New random seed ', randseed : 6, '.');
                Writeln(final_output, ' Final Output.', ' New random seed', randseed : 8, '.');
                Writeln(region_output, ' New random seed', randseed : 8, '.');
                if WritePeriodicStats then
                    Writeln(period_output, ' New random seed', randseed : 8, '.');
            end
        else
            begin                                                   {use old seed, which was inputed as constant}
                randseed := old_random_seed;
                Writeln(' Old random seed ', randseed : 6, '.');
                Writeln(final_output, ' Old random seed', randseed : 8, '.');
                Writeln(region_output, ' Old random seed', randseed : 8, '.');
                if WritePeriodicStats then
                    Writeln(period_output, ' Old random seed', randseed : 8, '.');
            end;
        if test then                                             {run number}
            run_number := 0
        else
            begin                   {not a test;  read run #}
                reset(datafile, Run_Number_File_Name);
                readln(datafile, run_number);
                run_number := run_number + 1;
                close(datafile);
                rewrite(datafile, Run_Number_File_Name);
                writeln(datafile, run_number);
                writeln('Run number', run_number : 4, '.');
                close(datafile);
                Writeln(final_output, 'Run number', run_number : 4, '.');
                Writeln(region_output, 'Run number', run_number : 4, '.');
                if WritePeriodicStats then
                    Writeln(period_output, 'Run number', run_number : 4, '.');
            end;    {if for run number }
    end;
 { ---------------------------------------------------------------  }
    procedure set_up_production_arrays;
        var
            itemp: integer;
    begin

        Xmax_value[1] := Xmax1;     {assume square map, so Ymax set in main program}
        Xmax_value[2] := Xmax2;
        Xmax_value[3] := Xmax3;
        Xmax_value[4] := Xmax4;
        Xmax_value[5] := Xmax5;
        for itemp := 1 to N_xmax do
            begin                                           {check enough space reserved for the map}
                if Xmax_tops < Xmax_value[itemp] then
                    begin
                        writeln('**** Halted because Xmax_tops not set big enough ****');
                        writeln(final_output, ' * * * * Halted because Xmax_tops not set big enough * * * * ');
                        moveto(h_offset, 30);
                        drawstring(' * * * * Halted because Xmax_tops not set big enough * * * * ');
                        halt;
                    end;
            end;
        Interaction_Types_value[1] := Interaction_types1;
        Interaction_Types_value[2] := Interaction_types2;
        Interaction_Types_value[3] := Interaction_types3;
        Interaction_Types_value[4] := Interaction_types4;
        Interaction_Types_value[5] := Interaction_types5;
        bitmax_value[1] := bitmax1;
        bitmax_value[2] := bitmax2;
        bitmax_value[3] := bitmax3;
        bitmax_value[4] := bitmax4;
        bitmax_value[5] := bitmax5;
        allelemax_value[1] := allelemax1;
        allelemax_value[2] := allelemax2;
        allelemax_value[3] := allelemax3;
        allelemax_value[4] := allelemax4;
        allelemax_value[5] := allelemax5;
    end;
{ ---------------------------------------------------------------  }
    procedure set_up_move_definitions;
    begin
        Xmove[1] := 0;                  {define North, in seeking neighbors}
        Ymove[1] := -1;
        Xmove[2] := 1;                  {define East}
        Ymove[2] := 0;
        Xmove[3] := -1;                 {define West}
        Ymove[3] := 0;
        Xmove[4] := 0;                  {define South}
        Ymove[4] := 1;
        Xmove[5] := 1;                  {define NE}
        Ymove[5] := -1;
        Xmove[6] := 1;                  {define SE}
        Ymove[6] := 1;
        Xmove[7] := -1;                 {define SW}
        Ymove[7] := 1;
        Xmove[8] := -1;                 {define NW}
        Ymove[8] := -1;
        Xmove[1 + 8] := 0;              {define  2 North}
        Ymove[1 + 8] := -2;
        Xmove[2 + 8] := 2;              {define 2 East}
        Ymove[2 + 8] := 0;
        Xmove[3 + 8] := -2;         {define 2 West}
        Ymove[3 + 8] := 0;
        Xmove[4 + 8] := 0;              {define  2 South}
        Ymove[4 + 8] := 2;
        Xmove[1 + 12] := 0;                 {repeat for directions 13-16: repeat North}
        Ymove[1 + 12] := -1;
        Xmove[2 + 12] := 1;                 {repeat East}
        Ymove[2 + 12] := 0;
        Xmove[3 + 12] := -1;                    {repeat West}
        Ymove[3 + 12] := 0;
        Xmove[4 + 12] := 0;                 {repeat South}
        Ymove[4 + 12] := 1;
    end;
{ ---------------------------------------------------------------  }
    procedure Initialize_run;
        var
            temp: integer;  {for tab index}
    begin
        cyclemax := round(cyclemax_float);
        culture := Culture_Array_Handle(NewHandle(sizeof(Culture_Array)));
        done := done_Array_Handle(NewHandle(sizeof(done_Array)));
        r_dis := distance_Array_Handle(NewHandle(sizeof(distance_Array)));
        d_dis := distance_Array_Handle(NewHandle(sizeof(distance_Array)));
        X_region := location_Array_Handle(NewHandle(sizeof(location_Array)));
        Y_region := location_Array_Handle(NewHandle(sizeof(location_Array)));
        origin_first_bit := distance_Array_Handle(NewHandle(sizeof(distance_Array)));
        if broadcast_rate_per_10000_cycles > 0 then
            begin
                broadcast_count := 0;
                broadcast_allowed := true;              {next line: to compare to -32768 to 32767}
                broadcast_cutoff_number := round((broadcast_rate_per_10000_cycles / 10000.0) * 65536.0 - 32768.0);
{writeln('broadcast_cutoff_number', broadcast_cutoff_number : 6);       }
            end;
        write_run_info;                                 {write run parameters to files}
        write('Case ');
        if mapmax <> 1 then             {repeating the same map}
            Write('Map  ');
        writeln('Pop    Xmax    Neigh   String  Alleles Clear   Period  Xmax    Regions tot dis # zero dis');
        write(final_output, 'Case   ');
        if mapmax <> 1 then
            Write(final_output, 'Map    ');
        writeln(final_output, 'Pop  Xmax    Neigh   String  Alleles Clear   Period  Xmax    Regions tot dis # zero dis');
        if WriteRegionStatsAtEnd = true then
            writeln(region_output, 'Case    Map Pop Region  X   Y   Size    Cul....then Distance to prev region');
        if graphics then
            begin
                create_graphics_window;
                initialize_graphics_window
            end;
        if WritePeriodicStats then
            begin
                writeln(period_output, 'case    map pop period     cycle    dist    #0 dist regions changes zones');
            end;
        set_up_production_arrays;
        if Interaction_Types_Tops > 16 then
            begin
                writeln('*** Error in setting contant: Interaction_Types_Tops > 16. Program halted. ***');
                halt;
            end;
        set_up_move_definitions;
    end; {initialize run procedure}
 { ---------------------------------------------------------------  }

    procedure write_graphics_report;
    begin
        frame_rectangle;            {to restore outer edge}
        forecolor(whitecolor);                              {update text at bottom}
        paintrect(10 + v_offset, h_offset, 30 + v_offset, 180 + h_offset);
        forecolor(blackcolor);
        moveto(h_offset, 18 + v_offset);
        drawstring(concat('Period =', stringof(period : 5)));
        if cyclemax <> 1000 then
            drawstring(concat('  (Each period is', stringof(cyclemax : 8), ' cycles.)'));
        if Graph_distance then
            begin
                moveto(h_offset, w * ymax_tops + 30 + v_offset);
                drawstring(concat('Sum of distances =', stringof(bit_distance_sum : 4)));
                moveto(h_offset, w * ymax_tops + 50 + v_offset + period);
                penNormal;
                line(bit_distance_sum, 0);      {draw horizontal line}
                pensize(pen_size, pen_size);        {restore size of pen}
            end; {graph cultural distance}
    end;
 { ---------------------------------------------------------------  }
    procedure Initialize_pop;
        var
            x, y: integer;                                      {local variable for coord of an individual}
            bit: integer;                                       {local variable for number of gene on the cultrual chormosome}
    begin
        if TextGridReport then
            writeln('Pop ', pop : 3, ':');
        NoMatchPopCount := 0;                   {count of times no match is found}
        for x := 1 to xmax do
            begin
                for y := 1 to ymax do
                    begin
                        for bit := 1 to bitmax do
                            begin                                           {initial culture for internal places}
                                culture^^[x, y, bit] := Random_one_to_n(allelemax) - 1;     {0..allelemax-1, sarting org13}
                            end;
                        origin_first_bit^^[x, y] := Xmax * (y - 1) + x - 1;         {record origin of the first bit, 00 to 99 for 10x10 map}
                    end;
            end; {x loop}
        if stack_map then
            begin
                map_x_offset := 0;                  {draw maps on top of each other}
                map_y_offset := 0
            end
        else
            begin                                       {write maps in rows for same initial conditions}
                map_x_offset := (w * xmax + 10) * (pop - 1);
                map_y_offset := (w * ymax + 10) * (map - 1);
            end;
    end; {initialize_pop procedure}
  { ---------------------------------------------------------------  }
    procedure Initialize_period;
    begin
        Changes_This_Period := 0;           {count of number of actual cultural changes in this period}
    end; {initialize_period procedure}
  { ---------------------------------------------------------------  }
    procedure report_change_test1;          {from interact procedure. reports first 5 bits.}
    begin
        writeln('report_converge_test1.match=', match : 2, '  ix=', ix : 3, '. iy=', iy : 3, ' ini cul = ', culture^^[ix, iy, 1] : 1, culture^^[ix, iy, 2] : 1, culture^^[ix, iy, 3] : 1, culture^^[ix, iy, 4] : 1, culture^^[ix, iy, 5] : 1);
{writeln('report_converge_test1. jx=', jx : 3, '. jy=', jy : 3, ' init cul = ', culture^^[jx, jy, 1] : 1, culture^^[jx, jy, 2] : 1, culture^^[jx, jy, 3] : 1, culture^^[jx, jy, 4] : 1, culture^^[jx, jy, 5] : 1);}
    end;
  { ---------------------------------------------------------------  }
    procedure report_change_test2;          {from interact procedure}
    begin
        writeln('report_change_test2. ix=', ix : 3, '. iy=', iy : 3, 'js new bit=', bit : 2, '. new cul = ', culture^^[ix, iy, 1] : 1, culture^^[ix, iy, 2] : 1, culture^^[ix, iy, 3] : 1, culture^^[ix, iy, 4] : 1, culture^^[ix, iy, 5] : 1);
{    writeln('report_change_test2. jx=', jx : 3, '. jy=', jy : 3, 'js new bit=', bit : 2, '. new cul = ', culture^^[jx, jy, 1] : 1, culture^^[jx, jy, 2] : 1, culture^^[jx, jy, 3] : 1, culture^^[jx, jy, 4] : 1, culture^^[jx, jy, 5] : 1);}
    end;
  { ---------------------------------------------------------------  }
    procedure change_if_possible_toward_neigh;                  {i converges one bit to j if possible}
        var
            try_another_bit: boolean;       {control on whether still searching for another bit that differs}
            bit_count: integer;             {count so as to give up when all bit tried, ie x=y}
            bit_try: integer;               {bit being tried looking for dissimilarity}
    begin
{    report_change_test1;}
        bit_try := random_one_to_n(bitmax);         {initial bit location tried}
        try_another_bit := true;
        bit_count := 1;
        repeat
            if culture^^[ix, iy, bit_try] <> culture^^[jx, jy, bit_try] then
                begin
                    culture^^[ix, iy, bit_try] := culture^^[jx, jy, bit_try];       {i converges since unequal on current bit}
                    try_another_bit := false;                               { done with search }
                    Changes_This_Period := Changes_This_Period + 1;     {to count actual number of changes, cf interact from broadcast}
                    if bit_try = 1 then                                                 {update where the first bit came from}
                        origin_first_bit^^[ix, iy] := origin_first_bit^^[jx, jy];
                end
            else
                begin
                    bit_count := bit_count + 1;
                    bit_try := (bit_try + 1) mod bitmax + 1;
                    if bit_count > bitmax then                      {give up because just tried all bits}
                        try_another_bit := false;
                end;
        until try_another_bit = false;

{    report_change_test2;}
    end;{interact procedure}
{------------------------------------------------------------}
    procedure interact_from_neighbor;
    begin
        repeat                                              {get an internal direction}
            direction := random_one_to_n(Interaction_Types);        {select location for interaction}
            if flat_map then
                begin
                    jx := ix + xmove[direction];                {cacl  coords of selected neighbor, j}
                    jy := iy + ymove[direction]
                end
            else        {torus map}
                begin                               {note: have to add Xmax or Ymax to be sure to get positive number}
                    jx := (ix + xmove[direction] - 1 + Xmax) mod xmax + 1;              {cacl  coords of selected neighbor, j}
                    jy := (iy + ymove[direction] - 1 + Ymax) mod ymax + 1;
                end;
        until ((flat_map = false) or ((jx > 0) and (jx < XMaxPlus1) and (jy > 0) and (jy < YMaxPlus1)));
                        {other is in legal area}
        match := (culture^^[ix, iy, bit] = culture^^[jx, jy, bit]);   {match is true or false}
{writeln('test3. match=', match : 3, ' iy=', iy : 4, '. y direction = ', direction : 4, ' . ymove = ', ymove[direction] : 4);}
        if match then                   {if the chosen bit of the selected neighbor matches then  interact }
            change_if_possible_toward_neigh                     {ie do only one interaction, as in Org 06}
    end;
{ ---------------------------------------------------------------  }
    procedure change_if_possible_toward_broadcast;                  {i converges one bit to j if possible}
        var
            try_another_bit: boolean;       {control on whether still searching for another bit that differs}
            bit_count: integer;             {count so as to give up when all bit tried, ie x=y}
            bit_try: integer;               {bit being tried looking for dissimilarity}
    begin
{report_change_test1;}
        bit_try := random_one_to_n(bitmax);         {initial bit location tried}
        try_another_bit := true;
        bit_count := 1;
        repeat
            if culture^^[ix, iy, bit_try] <> 0 then
                begin
                    culture^^[ix, iy, bit_try] := 0;        {i converges since unequal on current bit}
                    Changes_This_Period := Changes_This_Period + 1;     {to count actual number of changes, cf change to neighbor}
                    try_another_bit := false;                               { done with search }
                end
            else
                begin
                    bit_count := bit_count + 1;
                    bit_try := (bit_try + 1) mod bitmax + 1;
                    if bit_count > bitmax then                      {give up because just tried all bits}
                        try_another_bit := false;
                end;
        until try_another_bit = false;

{report_change_test2;}
    end;{interact procedure}
{------------------------------------------------------------}
    procedure interact_from_broadcast;
    begin
{broadcast_count := broadcast_count + 1;            }
        match := culture^^[ix, iy, bit] = 0;   {match is true or false}
{writeln('test3. match=', match : 3, ' iy=', iy : 4, '. y direction = ', direction : 4, ' . ymove = ', ymove[direction] : 4);}
        if match then                   {if the chosen bit of the selected neighbor matches then  interact }
            change_if_possible_toward_broadcast                     {ie do only one interaction, as in Org 06}
    end;
{ ---------------------------------------------------------------  }
    procedure mutate;                   {mutate for drift}
        var
            num_mutations: integer;             {number of mutations to perform this cycle}
            mut: integer;                           {index of mutations}
            old_allele, new_allele: integer;
    begin
        num_mutations := ipoisn(mutuation_rate_perpop_percycle);        {calc number of mutations}
{writeln(num_mutations : 3, '   n muts');       }
{test}
        for mut := 1 to num_mutations do                        {each mutation}
            begin
                ix := random_one_to_n(xmax);
                iy := random_one_to_n(ymax);
                bit := random_one_to_n(bitmax);
                Old_allele := culture^^[ix, iy, bit];                   {mutate to a DIFFERENT value 1...allelemax}
                New_allele := random_one_to_n(allelemax - 1) - 1;   {allele-1 corrected ver 1.5; should have been ver 1.3}
                if new_allele = old_allele then
                    new_allele := allelemax;                                {   if initially no change, use this for maxallele}
                culture^^[ix, iy, bit] := new_allele;
            end;{mutations loop}
    end;{mutate procedure}
  { ---------------------------------------------------------------  }
    procedure report_output_period_test;            {from output_period procedure}
        var                                                     {reports first five bits of culture}
            xtemp, ytemp: integer;
    begin
        for ytemp := 1 to ymax do
            begin
                write(' y=', ytemp : 3, '. Cul(1..5)=');
                for xtemp := 1 to xmax do
                    begin
                        write(culture^^[xtemp, ytemp, 1] : 3, culture^^[xtemp, ytemp, 2] : 1, culture^^[xtemp, ytemp, 3] : 1, culture^^[xtemp, ytemp, 4] : 1, culture^^[xtemp, ytemp, 5] : 1);
                    end;{ixtemp}
                writeln;
            end; {iytemp}
    end;
  { ---------------------------------------------------------------  }
    procedure set_pen_pat (bit_distance: integer);
    begin
        if bit_distance = 0 then
            penpat(white)
        else if bit_distance = 1 then
            penpat(ltgray)
        else if bit_distance = 2 then
            penpat(gray)
        else if bit_distance = 3 then
            penpat(dkgray)
        else
            penpat(black);
    end;
  { ---------------------------------------------------------------  }
    procedure draw_right_boundary (xtemp: integer; ytemp: integer);
        var
            bit_distance: integer;
    begin
        bit_distance := r_dis^^[xtemp, ytemp];
        set_pen_pat(bit_distance);
        move(0, pen_size);
        line(0, w - 2 * pen_size);
        move(w, -w + pen_size);
    end;
  { ---------------------------------------------------------------  }

    procedure draw_bottom_boundary (xtemp: integer; ytemp: integer);
        var
            bit_distance: integer;
    begin
        bit_distance := d_dis^^[xtemp, ytemp];
        set_pen_pat(bit_distance);
        line(w - 2 * pen_size, 0);
        if xtemp <= Last_X_Boundary then                            {draw intersection}
            begin                                               {find max distance around interection}
                if (r_dis^^[xtemp, ytemp] > bit_distance) then
                    bit_distance := r_dis^^[xtemp, ytemp];
                if (d_dis^^[xtemp + 1, ytemp] > bit_distance) then
                    bit_distance := d_dis^^[xtemp + 1, ytemp];
                if (r_dis^^[xtemp, ytemp + 1] > bit_distance) then
                    bit_distance := r_dis^^[xtemp, ytemp + 1];
                set_pen_pat(bit_distance);
                move(pen_size, 0);
                line(0, 0);                                         {to draw intersection}
                move(pen_size, 0);
            end;
    end;
  { ---------------------------------------------------------------  }
    procedure draw_distance_graph;
        var
            xtemp, ytemp: integer;          {geo loc}
    begin
        moveto(h_offset, 10);               {10 is space needed for header on drawing window}
        for ytemp := 1 to ymax do
            begin
                moveto(w + h_offset - pen_size + map_x_offset, w * (ytemp - 1) + v_offset + map_y_offset + 30);
                for xtemp := 1 to Last_X_Boundary do
                    begin
                        draw_right_boundary(xtemp, ytemp);
                    end;{xtemp}
                moveto(h_offset + map_x_offset, (w) * ytemp + v_offset + map_y_offset + 30);
                if (ytemp <= Last_Y_Boundary) then
                    begin
                        for xtemp := 1 to xmax do  {write row for distances down, only if not last row}
                            draw_bottom_boundary(xtemp, ytemp);     {including intersection}
                    end; {if not last row}
            end; {ytemp}
        write_graphics_report;
    end;
  { ---------------------------------------------------------------  }
    procedure CalcDistance;                 {cultural distances with output}
        type
            row_array = array[1..xmax_tops] of integer;         {for output of distances}
        var
            xtemp, ytemp: integer;          {geo loc}
            itemp: integer;                     {bit position}
            X_distance: row_array;          {cultural distance between (x,y) to (x+1,y), ie to right }
            Y_distance: row_array;          {cultural distance between (x,y) to (x,y+1), ie down }
    begin
        bit_distance_sum := 0;                  {initialize sum of bit distances to neighbors (over current cycle)}
        n_zero_distance := 0;                   {initialize num of boundaries with zero bit distance}
        for ytemp := 1 to ymax do
            begin
                for xtemp := 1 to xmax do
                    begin
                        X_distance[xtemp] := 0;             {calcs will be for one row at a time}
                        Y_distance[xtemp] := 0;
                        for itemp := 1 to bitmax do
                            begin                                           {increment distance on x axis, then y axis}
                                if flat_map then            {flat map}
                                    begin
                                        if xtemp <= Last_X_Boundary then                        {to avoid going off right side, unless torus}
                                            if culture^^[xtemp, ytemp, itemp] <> culture^^[xtemp + 1, ytemp, itemp] then
                                                X_distance[xtemp] := X_distance[xtemp] + 1;
                                        if (ytemp <= Last_Y_Boundary) then                  {only do down calcs if not last row}
                                            begin
                                                if (culture^^[xtemp, ytemp, itemp] <> culture^^[xtemp, ytemp + 1, itemp]) then
                                                    Y_distance[xtemp] := Y_distance[xtemp] + 1
                                            end; {if not last row}
                                    end
                                else                            {torus}
                                    begin                                       {note its xtemp, not xtemp+1 now in next line}
                                        if culture^^[xtemp, ytemp, itemp] <> culture^^[(xtemp) mod xmax + 1, ytemp, itemp] then
                                            X_distance[xtemp] := X_distance[xtemp] + 1;
                                        if (culture^^[xtemp, ytemp, itemp] <> culture^^[xtemp, (ytemp) mod ymax + 1, itemp]) then
                                            Y_distance[xtemp] := Y_distance[xtemp] + 1
                                    end;
                            end; {itemp loop for culture bits}
                        bit_distance_sum := bit_distance_sum + X_distance[xtemp] + Y_distance[xtemp];   {sum of bit dists at end of periods}
                        r_dis^^[xtemp, ytemp] := X_distance[xtemp];
                        d_dis^^[xtemp, ytemp] := Y_distance[xtemp];
                        if (X_distance[xtemp] = 0) and (xtemp <= Last_X_Boundary) then
                            n_zero_distance := n_zero_distance + 1;
                        if (Y_distance[xtemp] = 0) and (ytemp <= Last_Y_Boundary) then
                            n_zero_distance := n_zero_distance + 1;
                    end; {xtemp loop for calc distances}
                if TextGridReport then
                    write('y= ', ytemp : 3, '. Dis across: ');
                for xtemp := 1 to Last_X_Boundary do
                    begin  {write row for across distances}
                        if TextGridReport then
                            write(' ', X_distance[xtemp] : 3);
                    end; {xtemp for writing row for across distances}
                if TextGridReport then
                    writeln;
                if (ytemp <= Last_Y_Boundary) then
                    if TextGridReport then
                        write('y= ', ytemp : 3, '. Dis down: ');
                if (ytemp <= Last_Y_Boundary) then
                    begin
                        for xtemp := 1 to xmax do
                            begin  {write row for distances down}
                                if TextGridReport then
                                    write(' ', Y_distance[xtemp] : 3);
                            end; {xtemp for writing row for  distances down}
                        if TextGridReport then
                            writeln;
                    end; {if not last row}
            end;  {ytemp loop}
        if TextGridReport then
            writeln;
        if graphics then
            draw_distance_graph;
    end;
  { ---------------------------------------------------------------  }
    function dis (x: x_type; y: y_type; direction: direction_type): integer;    {returns bit distance in a direction}
        var
            xnew, ynew: integer;            {to calc wrap-around}
    begin               {used in Visit}
        if flat_map then
            begin
                if direction = 1 then               {dir=North}
                    dis := d_dis^^[x, y - 1];
                if direction = 2 then               {dir = E}
                    dis := r_dis^^[x, y];
                if direction = 3 then               {dir = W}
                    dis := r_dis^^[x - 1, y];
                if direction = 4 then               {dir = S}
                    dis := d_dis^^[x, y];
            end
        else                            {torus. Compare to flat map method above}
            begin
                if direction = 1 then               {dir=North}
                    begin
                        if y = 1 then
                            ynew := ymax
                        else
                            ynew := y - 1;
                        dis := d_dis^^[x, ynew];
                    end;
                if direction = 2 then               {dir = E}
                    dis := r_dis^^[x, y];
                if direction = 3 then               {dir = W}
                    begin
                        if x = 1 then
                            xnew := xmax
                        else
                            xnew := x - 1;
                        dis := r_dis^^[xnew, y];
{writeln(Region_Output, 'Test333.  x = ', x : 2, '. y = ', y : 2, ' ix = ', ix : 2, ' . iy = ', iy : 2, ' . jx = ', jx : 2, ' . jy = ', jy : 2, ' . cult = ', culture^^[jx, jy, 1], culture^^[jx, jy, 2]);}
                    end;
                if direction = 4 then               {dir = S}
                    dis := d_dis^^[x, y];
            end;
    end;
{ ---------------------------------------------------------------  }
    procedure Visit (x: x_type; y: y_type; critical_dist: integer);                         {from Analyze_regions}
        var
            xq: array[1..10000] of x_type;                          {space is no bigger than 100x100}
            yq: array[1..10000] of y_type;
            direction: direction_type;
            checkA: boolean;
    begin
        region_size := 0;
        iq := iq + 1;               {add node to ready queue}
        xq[iq] := x;
        yq[iq] := y;
        while iq > 0 do         {while ready queue not empty...}
            begin
                ix := xq[iq];               {get node from end of ready queue}
                iy := yq[iq];
                iq := iq - 1;
                for direction := 1 to 4 do   {add to ready queue the neighobrs who are legal, not done, and  0 dist }
                    begin
                        jx := ix + xmove[direction];                {cacl  coords of selected neighbor, j}
                        jy := iy + ymove[direction];
                        if not flat_map then            {correct for torus}
                            begin
                                if jx > xmax then                   {ok because movement here is only one site}
                                    jx := 1;
                                if jx = 0 then
                                    jx := xmax;
                                if jy > ymax then
                                    jy := 1;
                                if jy = 0 then
                                    jy := ymax;
                            end;
{write('Test222. ix=', ix : 3, '. iy=', iy : 3, '. jx=', jx : 3, '. jy= ', jy : 3, '. cult=', culture^^[jx, jy, 1], culture^^[jx, jy, 2]);}
{writeln(' done^^[jx,jy ] ', done^^[jx, jy]);}
                        if (flat_map and (culture^^[jx, jy, 1] <> -1)) then
                            checkA := true
                        else
                            checkA := false;
{writeln(' test 555 ', checkA, flat_map, not flat_map, flat_map = false, checkA or not flat_map, (checkA or (flat_map = false)));}
                        if ((checkA or not flat_map) and (not done^^[jx, jy])) then
                            begin
                                if dis(ix, iy, direction) <= critical_dist then         {crit distance = 0 for region, bitmax-1 for zone}
                                    begin
                                        iq := iq + 1;               {add this valid neighbor to ready queue}
                                        xq[iq] := jx;
                                        yq[iq] := jy;
                                        done^^[jx, jy] := true;             {change its status to done}
                                        region_size := region_size + 1;
{writeln('test 11/21. jx, jy, culture^^[jx, jy, 1]', jx, jy, culture^^[jx, jy, 1]);}
                                    end; {if dis< min}
                            end;{if  legal and not done}
                    end;{direction}
            end; {while iq>0}
        if region_size = 0 then
            region_size := 1;               {needed for 1x1 regions which have no valid neighbors}
    end;
  { ---------------------------------------------------------------  }
    procedure Ck_Equal_Cultures;            {from Analyze Regions}
        var
            x, x2: x_type;      {}
            y, y2: y_type;
            bit: integer;           {local index of cultural bit}
            r, r2: integer;         {local indices of regions}
            cultures_same: boolean;  {two regions have same culture}
    begin
        for r := 1 to regions do
            begin
                x := x_region^^[r];
                y := y_region^^[r];
                for r2 := 1 to r - 1 do
                    begin
                        x2 := x_region^^[r2];
                        y2 := y_region^^[r2];
                        bit := 0;
                        cultures_same := true;
                        repeat
                            begin
                                bit := bit + 1;
                                if culture^^[x, y, bit] <> culture^^[x2, y2, bit] then
                                    cultures_same := false;
                            end;
                        until (not cultures_same) or (bit = bitmax);
                        if cultures_same then
{writeln('Culture of  (', x : 2, y : 2, ')=Culture of (', x2 : 2, y2 : 2, ').');        }
                    end;
            end;
    end;
  { ---------------------------------------------------------------  }
    procedure Report_Per_Region (x: x_type; y: y_type);     {from Analyze_Regions}
        var
            r2: integer;        {regional count}
            x2: x_type;
            y2: y_type;
            culture_dis: integer;
            bit_temp: bit_type;
    begin
        write('R ', regions : 3, ' (', x : 2, ',', y : 2, '). Sz =', region_size : 3);
        write('. Cul= ');
        for bit_temp := 1 to bitmax do
            begin
                write(culture^^[x, y, bit_temp] : 2);
            end;
        write('.  D to prev regs = ');
        for r2 := 1 to regions - 1 do
            begin
                x2 := x_region^^[r2];
                y2 := y_region^^[r2];
                culture_dis := 0;
                for bit_temp := 1 to bitmax do
                    begin
                        if culture^^[x, y, bit_temp] <> culture^^[x2, y2, bit_temp] then
                            culture_dis := culture_dis + 1;
                    end;
                write(culture_dis : 3);
            end;{r}
        writeln;
    end;

  { ---------------------------------------------------------------  }
    function Map_Clear: boolean;    {are all boundaries 0 or bitmax?}
{not used starting Org 14}
        var
            boundaries, distance_if_clear: longint;
    begin
        boundaries := (Last_X_Boundary) * ymax + xmax * (Last_Y_Boundary);  {# boundaries down and across}
        distance_if_clear := bitmax * (boundaries - n_zero_distance);
        if distance_if_clear = bit_distance_sum then
            map_clear := true
        else
            map_clear := false;
    end;
  { ---------------------------------------------------------------  }
    function Neighbor_Clear: boolean;   {are all neighobrs 0 or bitmax?}
        var                     {added at Org14}
            ix, iy, jx, jy, direction, bit: integer;    {temp local variables}
            match_count: integer;
        label
            1;
    begin
        neighbor_clear := true;    {assume all neighbors are 0 or bitmax from all sites}
        for ix := 1 to Xmax do
            begin
                for iy := 1 to Ymax do
                    begin
                        for direction := 1 to Interaction_Types do
                            begin
                                if flat_map then
                                    begin
                                        jx := ix + xmove[direction];                {cacl  coords of selected neighbor, j}
                                        jy := iy + ymove[direction]
                                    end
                                else                                                    {torus map}
                                    begin                               {note: have to add Xmax or Ymax to be sure to get positive number}
                                        jx := (ix + xmove[direction] - 1 + Xmax) mod xmax + 1;              {cacl  coords of selected neighbor, j}
                                        jy := (iy + ymove[direction] - 1 + Ymax) mod ymax + 1;
                                    end;
                                if ((flat_map = false) or ((jx > 0) and (jx < XMaxPlus1) and (jy > 0) and (jy < YMaxPlus1))) then
                                    begin                                      {legal neighbor. Note any neigh is legal if flat_map= false }
                                        match_count := 0;
                                        for bit := 1 to bitmax do
                                            begin
                                                if (culture^^[ix, iy, bit] = culture^^[jx, jy, bit]) then
                                                    match_count := match_count + 1;
                                            end; {bit}
                                        if (match_count > 0) and (match_count < bitmax) then
                                            begin
                                                neighbor_clear := false;
                                                goto 1;             {leave if a neighbor is not clear}
                                            end;
                                    end; {legal neighbor}
                            end;{neighbor}
                    end; {it}
            end; {ix}
1:                              {go here here if a neighbor is not clear}
    end;
  { ---------------------------------------------------------------  }

    procedure Report_Final_Region (x: x_type; y: y_type);       {from Analyze_Regions}
        var                 {done if (WriteRegionStatsAtEnd) and (neighbor_clear = true)}
            r2: integer;        {regional count}
            x2: x_type;
            y2: y_type;
            culture_dis: integer;
            bit_temp: bit_type;
    begin
        write(region_output, case_number : 3, ' ', map : 3, '   ', pop : 3);
        write(region_output, '  ', regions : 3, '   ', x : 2, ' ', y : 2, ' ', region_size : 3);
        for bit_temp := 1 to bitmax do
            begin
                write(region_output, '  ', culture^^[x, y, bit_temp] : 2);
            end;
        for r2 := 1 to regions - 1 do
            begin
                x2 := x_region^^[r2];
                y2 := y_region^^[r2];
                culture_dis := 0;
                for bit_temp := 1 to bitmax do
                    begin
                        if culture^^[x, y, bit_temp] <> culture^^[x2, y2, bit_temp] then
                            culture_dis := culture_dis + 1;
                    end;
                write(region_output, '  ', culture_dis : 3);
            end;{r}
        writeln(region_output);
    end;

  { ---------------------------------------------------------------  }
    procedure Analyze_regions;                      {count number of regions, and types}
        var     {based on breadth first search.See Stubbs and Webre, Data Structures, 359ff}
            x: x_type;
            y: y_type;
    begin
        regions := 0;
        iq := 0;                                    {initialize ready queue}
        for x := 1 to xmax do
            begin
                for y := 1 to ymax do
                    begin
                        done^^[x, y] := false;
                    end;
            end; {end initialization}
        for x := 1 to xmax do               {for each node...}
            begin
                for y := 1 to ymax do
                    begin
                        if not done^^[x, y] then    {if not done then record it and visit it}
                            begin
                                regions := regions + 1;         {count regions}
                                Visit(x, y, 0);                 {0 is min distance allowed for regions}
                                if WriteRegionStats then
                                    Report_Per_Region(x, y);
                                if (WriteRegionStatsAtEnd) and (neighbor_clear = true) then
                                    Report_Final_Region(x, y);
                                x_region^^[regions] := x;           {add loc to list of regions}
                                y_region^^[regions] := y;
                            end;
                    end;
            end; {for each node}
        Ck_Equal_Cultures;
{writeln('Period ', period : 4, '. Number of regions = ', regions : 4);}
    end;
  { ---------------------------------------------------------------  }
    procedure Analyze_zones;                        {count number of zones, and types. mod. from Analyze regions}
        var     {based on breadth first search.See Stubbs and Webre, Data Structures, 359ff}
            x: x_type;
            y: y_type;
            max_distance: integer;
    begin
        zones := 0;
        iq := 0;                                    {initialize ready queue}
        max_distance := bitmax - 1;     {a zone may have any distance, except maxmal}
        for x := 1 to xmax do
            begin
                for y := 1 to ymax do
                    begin
                        done^^[x, y] := false;
                    end;
            end; {end initialization}
        for x := 1 to xmax do               {for each node...}
            begin
                for y := 1 to ymax do
                    begin
                        if not done^^[x, y] then    {if not done then record it and visit it}
                            begin
                                zones := zones + 1;         {count regions}
                                Visit(x, y, max_distance);                  {0 is min distance allowed for regions}
                                x_region^^[regions] := x;           {add loc to list of regions}
                                y_region^^[regions] := y;
                            end;
                    end;
            end; {for each node}
        Ck_Equal_Cultures;
{writeln('Period ', period : 4, '. Number of regions = ', regions : 4);}
    end;
  { ---------------------------------------------------------------  }
    procedure Output_period;                        {output for a single period}
        var
            total_cycles: longint;
    begin
        if TextGridReport then
            report_output_period_test;                  {test output for this perod}
        CalcDistance;                       {Calc distance between neighbors}
        Analyze_regions;                    {Analyze number of regions, and their cultures}
        if WritePeriodicStats then
            begin
                Analyze_zones;              {Analyze number of zones - ie totally incompatible domains}
                total_cycles := period * cyclemax;
                Write(period_output, case_number : 5, ' ', map : 5, '   ', pop : 5, '   ', period : 5, '    ', total_cycles : 8);
                Write(period_output, '  ', bit_distance_sum : 5, '  ', n_zero_distance : 5, '       ', regions : 3, '   ', changes_this_period : 5);
                Writeln(period_output, '    ', zones : 3);
            end;
        if button then
            begin
                writeln('**** Halted by user ****');
                writeln(final_output, '**** Halted by user ****');
                halt;
            end;
    end;
  { ---------------------------------------------------------------  }
    procedure Output_pop;                       {output for a single population}
        var
            x, y: integer;
    begin
{write('End of Pop  ', pop : 3, '.  Per ', period : 3, '    . Map_Clear =', Map_Clear : 2, '.   ', regions : 3, '   regions.    ');}
{writeln(bit_distance_sum : 4, '    total dis.  ', n_zero_distance : 4, '   # zero dis.');}
        write(Case_Number : 4);
        if mapmax > 1 then
            write(' ', map : 3);
        write('     ', pop : 5, '   ', Xmax : 4, '  ', Interaction_types : 4, ' ', bitmax : 4, '    ', allelemax : 4, ' ');
        write(Map_Clear : 5, '  ', period : 6, '    ', Xmax : 4, '  ', regions, '   ');
        writeln(bit_distance_sum : 8, ' ', n_zero_distance : 4);
        write(final_output, Case_Number : 4);
        if mapmax > 1 then
            write(final_output, '   ', map : 3);
        write(final_output, '   ', pop : 5, '   ', Xmax : 4, '  ', Interaction_types : 4, ' ', bitmax : 4, '    ', allelemax : 4, ' ');
        write(final_output, Map_Clear : 5, '    ', period : 6, '    ', Xmax : 4, '  ', regions, '   ');
        writeln(final_output, bit_distance_sum : 8, '   ', n_zero_distance : 4);
        if report_bit_origin then                           {report first bit's origin}
            begin
                for y := 1 to ymax do
                    begin
                        write('Origin of first bit, y=  ', y : 3, '. ');
                        for x := 1 to xmax do
                            begin
                                write(origin_first_bit^^[x, y] : 5);
                            end; {x}
                        writeln;
                    end;{y}

            end; {report_bit_origin}

{    Write('TEST: String Length = ', bitmax : 3, '. Alleles=', allelemax : 3);  }
{    Write('. Prob diff=(1-1/A)**L=', exp(bitmax * ln(1 - 1 / allelemax)) : 10 : 4);}
{    Writeln('. Reciprocal =', 1 / exp(bitmax * ln(1 - 1 / allelemax)) : 10 : 4); }
{    writeln(' Test . Pop ', pop : 3, ' . Culture [ 011 ] = ', culture^^[0, 1, 1] : 2, ' . Culture [ 341 ] = ', culture^^[3, 4, 1] : 2);}
    end;
  { ---------------------------------------------------------------  }
    procedure initialize_edge_of_map;       {enter -1 just beyond edges; for regional analysis}
        var
            x, y, bit: integer;
    begin
        for x := 1 to xmax do                           {initialize ind's beyond the internal borders. Never changes.}
            begin
                for bit := 1 to bitmax do
                    begin
                        culture^^[x, 0, bit] := -1;         {initial culture for beyond top internal border}
                        culture^^[x, ymax + 1, bit] := -1;          {initial culture for beyond bottom internal }
                    end;
            end; {x}
        for y := 1 to ymax do                           {initialize indiv's beyond the internal borders. Never changes.}
            begin
                for bit := 1 to bitmax do
                    begin
                        culture^^[0, y, bit] := -1;         {initial culture for beyond left internal border}
                        culture^^[Xmax + 1, y, bit] := -1;          {initial for beyond right internal border}
                    end;
            end;{y}
    end;
{ ---------------------------------------------------------------  }
    procedure Output_Run;                       {Output for run - last thing written}
    begin
        gettime(end_datetime);
        end_hour := end_datetime.hour;          {to force long interger}
        end_time := 60 * 60 * end_hour + 60 * end_datetime.minute + end_datetime.second;
        duration := end_time - start_time;
        Writeln('Duration of this run is ', duration : 5, ' seconds.');
        Writeln(final_output, 'Duration of this run is ', duration : 5, ' seconds.');
{Writeln('Broadcast count=', broadcast_count : 4);      }
    end;
 { ---------------------------------------------------------------  }
    procedure Cycle_Loop;               {Assume Mthod B: do only one interaction when there is match}
        var                                     { Allow broadcasting}
            cycle: longint;                                     {current cycle (ie active indiv), 1..cyclemax}
    begin
        for cycle := 1 to cyclemax do                               {CYCLE of one active actor}
            begin
                ix := Random_one_to_n(Xmax);            {select X coord of active actor}
                iy := Random_one_to_n(Ymax);            {select Y coord of active actor}
                bit := random_one_to_n(bitmax);     {bit to be checked for match}
                if broadcast_allowed then           {do broadcast interaction}
                    if random < broadcast_cutoff_number then
                        interact_from_broadcast
                    else
                        interact_from_neighbor                  {braodcast allowed, but didn't happen this time}
                else        {do interaction with neighbor}
                    interact_from_neighbor;                 {broadcast not allowed}
                if mutuation_rate_perpop_percycle > 0.0 then
                    mutate;                         {mutate culture bits for drift}
            end; { cycle of one active }
    end;

{- - - - - - - - - - - - - - - - - ----------------- - - - - - - - - - - - - - - - - }
{ ---------------------------------------------------------------  }
{M A I N    P R O G R A M }
begin
    initialize_run;                                                             {initialize whole run}
    case_number := 0;                                                           {sequential count of pops}
    for Xmax_index := 1 to N_Xmax do
        begin
            Xmax := Xmax_value[Xmax_index];
            Ymax := Xmax;                                       {assume square map}
            XmaxPlus1 := Xmax + 1;
            YmaxPlus1 := Ymax + 1;
            XmaxYmax := Xmax * Ymax;
            if flat_map then
                begin
                    Last_X_Boundary := Xmax - 1;    {flat map}
                    Last_Y_Boundary := Ymax - 1;
                end
            else
                begin
                    Last_X_Boundary := Xmax;            {torus}
                    Last_Y_Boundary := Ymax;
                end;
            if graphics then
                frame_rectangle;
            for interaction_types_index := 1 to N_interaction_types do
                begin
                    interaction_types := interaction_types_value[interaction_types_index];
                    for bitmax_index := 1 to N_bitmax do
                        begin
                            bitmax := bitmax_value[bitmax_index];
                            initialize_edge_of_map;
                            for allelemax_index := 1 to N_allelemax do
                                begin
                                    allelemax := allelemax_value[allelemax_index];
                                    for map := 1 to mapmax do       {generate map starts}
                                        map_seed[map] := random;
                                    for pop := 1 to popmax do       {generate interaction starts}
                                        interaction_seed[pop] := random;
                                    for map := 1 to mapmax do           {do a map}
                                        begin
                                            for pop := 1 to popmax do                   {do a pop with current map}
                                                begin
                                                    randseed := map_seed[map];
{writeln('Map Repeat Test: randseed for this map=', randseed : 8);}
                                                    Initialize_pop;                                                     {INITIALIZE current population}
                                                    randseed := interaction_seed[pop];                  {to start interactions}
{writeln('Interaction Repeat Test: randseed to start interactions=', randseed : 8);}
                                                    case_number := case_number + 1;                             {sequential count of pops's}
                                                    period := 0;
                                                    repeat                               {REPORTING PERIOD }
                                                        begin
                                                            period := period + 1;
                                                            Initialize_Period;
                                                            Cycle_Loop;
                                                            Output_Period;                          {output of a period, incl regional analysis}
                                                        end;{period}
{until (period = periodmax) or (neighbor_clear = true);  }
                                                    until (period = periodmax);     {changed from prev line 10/30/96 for mutation}
{end pop at periodmax or neighbors are all 0 or bitmax}
                                                    Output_Pop;                                     {output of the population}
                                                end; {pop}
                                        end; {map}
                                end; {bitmax_index}
                        end;{allelemax_index}
                end;{interaction_type_index}
        end; {Xmax_index}
    Output_Run;                                     {output of the run}
end.{main program}

Back to Cultural Model Page
Back to Chapter 7
Back to Appendix A
Back to Appendix B
Back to Complexity of Cooperation Home Page

University of Michigan Center for the Study of Complex Systems
Contact cscs@umich.edu.
Revised December 20, 1996.