
      Documentation for writing C code to generate Cellsim rules
			     Cellsim V2.5


	       ****************************************
		      YOU MUST HAVE THE MAKEFILE
		     ("Use the Makefile, Luke!")

  To use the new method of writing your own rules, you must have a copy
of the file "Makefile" (which is in the directory "Rule_src" under the
"V2.5" directory of this distribution of Cellsim); you should have a copy
of the "Makefile" in the same directory as your C files for the rules.

  Note also that the second line of the Makefile, the definition of MDIR,
should point to the full pathname of the "Rule_mdir" directory under the
Cellsim V2.5 directory.  This is necessary, so that the C compiler will
know where to find the necessary include file, and the other C files it
needs to generate your rules.


	       ****************************************
		      WRITING AN UPDATE FUNCTION

  Update functions must be written in C.

  During the following documentation, you are advised to consult the files
"heat2.m256.c" and "life.m2" in the "Rule_src" directory, as examples of how
to write an update-function file for both 256-state computed-function rules,
and lookup-table rules.  Writing rules is really much simpler than this
documentation makes it sound; looking at the examples after you've read this
will clarify any confusion about the process, I hope.

  The first thing in your rule file (besides any comments) should be the line:

#include "nborhood.h"

  This will include definitions of the neighborhood structures and
variables, plus a few macros to extract the neighbors from the structures
for you.

  Next, you should declare all of the functions in your file.  You -must-
declare your update function here.  If you are using 256 states and will
be using "before" and "after" functions, you must declare them too.
An example of doing this is:

byte my_update_func();

  Your update function should return a "byte", which has been typedef'ed
to be an unsigned char.

  Next, if you are using 256 states, you should declare any static variables,
if you want any.  For example, the heat2.m256.c rule defines:

static int hsum=0;

as a private integer it will use.

  Note that the following variable names are reserved (they are defined in
the "nborhood.h" file):
     tl, l, bl, t, c, b, tr, r, br, ll, rr, lll, rrr, cw, ccw, opp, phase,
     x,y,time, parm1, parm2, center, north, south, east, west, northeast,
     southeast, northwest, southwest, clockwise, counterclockwise, and
     opposite.

So be sure you don't define your own variables that would conflict with
these.


  The first actual routine in your file must be an initialization routine,
which will be called once when the rule-file is first used.  This function
-must- have the name "init_function"! In this function, there is one thing
you are required to do: set the value of "update_function".  When using 256
states, this is necessary so that Cellsim will know what to call to update a
cell's value; when using fewer states, it is necessary so that the library
routines will know what function to call to generate the lookup table.
  For example, an initialization function could be:

void
init_function()
{
    update_function = my_update_func;
}

  Note that there are *not* parenthesis after "my_update_func".  This is
because we aren't calling my_update_func, we are using its name (actually
its address) in the assignment statement.  If you accidentally say something
like:  update_function = my_update_func();   then things will probably
crash when you try to run.

  Note that the following names are reserved; that is, you cannot use them
as the names of your own functions:

     initialization_function, update_function, before_function, after_function

Cellsim uses these names as pointers to your routines.

Note that if you are using 256 states, you can also set either or both of
the global parameters in your initialization function, by simply assigning
values to the variables "parm1" and "parm2".  If you are going to be doing
analysis or modifications on the image array before or after each time-step,
you can also set the values of the function-pointers "before_function" and
"after_function", just as you did for "update_function".  See heat2.m256.c
for a demonstration of this.
When using lookup-table rules, setting parm1 and/or parm2 will have no effect,
and trying to set either "before_function" or "after_function" will cause
an error when trying to compile your routine.


	       ****************************************
			 THE UPDATE FUNCTION

  When using 256 states, your update function will be called for every cell
in the array, every time step.  Therefore, if you run on a 64x64 array for
a couple hundred time steps, your update function will be called a million
times!  Because of this, you don't want to make your update function
unnecessarily complicated.  When using less than 256 states, your update
function will be called once for every possible neighborhood configuration,
to generate the lookup table (e.g. 512 times for the "m2" neighborhood).
Therefore, it's OK if your function is a little slow, since once the table
has been generated, your function won't be used again.

  Your update function will receive only one parameter; it will be a
pointer to a structure which contains all of the neighbors of the current
cell.  If you are using 256 states, the structure will also contain the
current values of parm1 and parm2, the current "time" (what time-step you
are currently on, as displayed in the Cellsim control panel), and x and y
coordinates of the current cell (only x coordinate, for linear neighborhoods).
You must declare that parameter as the appropriate type; the possible
neighborhood structures are:
     moore_nbors, vonn_nbors, margolus_nbors, lr1_nbors, lr2_nbors, lr3_nbors
Remember that the parameter is a pointer to a structure, so you would
declare the parameter for example as:
  moore_nbors *nbors;
where "nbors" is the parameter to your update-funtion.

  There are macros defined to extract these neighbors from their structure
and store them into local variables.  The name of the macro depends on the
neighborhood.  They are:
     Get_moore_nbors, Get_vonn_nbors, Get_margolus_nbors,
     Get_lr1_nbors, Get_lr2_nbors, Get_lr3_nbors

You call them by treating them as a simple statement, i.e. you simply say:

Get_moore_nbors;

  That will set the Moore-neighborhood variables:

tl, l, bl, t, c, b, tr, r, br

and   parm1, parm2, x, y, time   as well, if you are using 256 states

  which your function can then use.  Note that all of these variables are
integers, although they will only have 1-byte values in them.  They are
integers to prevent overflow problems that arise when you do arithmetic
with 1-byte (unsigned char) variables.  However, your function should
still return a 1-byte value.

  The rest of your function, after you've called the appropriate macro to
set the neighborhood variables, should be the actual code to compute the
new value of this cell.  A simple example of computating the new value of a
cell would be to add the values of the neighbors, and return the sum mod 4,
assuming you are using a neighborhood with at least 4 states/cell.
You wouldn't even need a local variable in your function to do this,
your whole update function could look like this:

byte
my_update_func(nbors)
moore_nbors *nbors;
{
    return (tl + l + bl + t + c + b + tr + r + br) % 4;
}


  That's all there is to it.


	       ****************************************
		    THE BEFORE AND AFTER FUNCTIONS

  If you are using 256 states, then in addition to the update function, you
can also write an analysis function to be called before the array is updated,
and another one to be called after the array is updated, if you like.  These
functions can be set in the initialization routine, as described above.
  This feature is not available for lookup-table rules, so that they can
run as fast as possible.  If you need this feature for a 4-state rule, for
example "myrule.v4.c", then rename your file to "myrule.v256.c" so that it
will be used as a computed-function rule rather than a lookup-table rule.
This will let you use the before and after functions; your update function 
will have to make sure it only returns values between 0 and 3, however, if
that is what you want.
  The before and after functions each receive one argument, which is a
pointer to a structure containing: a pointer to the current array, the
current time, the size of the array, and the two global parameters parm1
and parm2.  The precise definition of this
structure is:

typedef struct {
    unsigned char *array;
    int time;
    int size;
    int parm1, parm2;
} array_info_struct;

The array is stored as a linear array of bytes; the first byte is the
upper-left cell, the second byte is the second cell on the first row, and
so on.  You can modify the contents of the array if you wish, or simply
perform some data analysis and perhaps print out some numbers or store
them in a file.  (You can open a file from your initialization function).


	       ****************************************
		   COMPILING YOUR UPDATE FUNCTIONS

  If your rule is a 256-state rule, you can simply compile your update
function by saying, for example:
    cc -c myrule.m256.c
which will generate a file "myrule.m256.o" which you can then
load into Cellsim.
  However, since you already had to copy the Makefile from the "Rule_src"
directory into the current directory, you can just use the "make" utility
to compile your rule.  To do so, you would type:
  make myrule.m256
and it would generate a file "myrule.m256.sun3.o" (or sun4, if that is what
you are running on).

  The Makefile will also work for non-computed-function (lookup-table) rules;
for example if you had a file "myrule.v8.c", you could simply say:
  make myrule.v8
and it would compile your C file, along with another C file supplied as
part of Cellsim, which contains the main() which loops through all possible
neighborhoods.  It would then generate a temporary executable file to call
your routines, generate the lookup table, and write the table out to the
file "myrule.v8".  So after you've typed "make myrule.v8" there would be a
file called "myrule.v8" in the current directory, which is the lookup-table
file.

  You can also edit the Makefile to tell it where to deposit the lookup-tables
and/or ".o" files once they have been generated.


/*
 *
 * Cellsim copyright 1989, 1990 by Chris Langton and Dave Hiebeler
 * (cgl@lanl.gov, hiebeler@heretic.lanl.gov)
 *
 * This package may be freely distributed, as long as you don't:
 * - remove this notice
 * - try to make money by doing so
 * - prevent others from copying it freely
 * - distribute modified versions without clearly documenting your changes
 *   and notifying us
 *
 * Please contact either of the authors listed above if you have questions
 * or feel an exception to any of the above restrictions is in order.
 *
 * If you make changes to the code, or have suggestions for changes,
 * let us know!  If we use your suggestion, you will receive full credit
 * of course.
 */

/*****
 * Cellsim history:
 *
 * Cellsim was originally written on Apollo workstations by Chris Langton.
 *
 * Sun versions:
 *
 * - version 1.0
 *   by C. Ferenbaugh and C. Langton
 *   released 09/02/88
 *
 * - version 1.5
 *   by Dave Hiebeler and C. Langton  May - June 1989
 *   released 07/03/89
 *
 * - version 2.0
 *   by Dave Hiebeler and C. Langton  July - August 1989
 *   never officially released (unofficially released 09/08/89)
 *
 * - version 2.5
 *   by Dave Hiebeler and C. Langton  September '89 - February 1990
 *   released 02/26/90
 *****/
