Programming user rules in MCell

Go back to MCell Home

Beginning with the version 2.0.0.205 of MCell users can program new rules that do not have to obey limits of any predefined CA families. This page is a short tutorial on programming own Cellular Automata.

Overview

User rules are programmed as stand alone DLLs that are dynamically loaded to MCell at runtime. One can compile them using any Windows 32-bit compiler supporting __stdcall (or _pascal) method of passing parameters. Provided examples show programming user DLLs in Microsoft Visual C 6.0, Borland Delphi 4.0/5.0, and in Borland C++ Builder 3.0/4.0; one should however have no problems with other compilers.

A simple example

One example tells more than thousands of words, so let's first look at a simple example in C:

/////////////////////////////
// Sample 2D rule - Conway's Life with decay
// Calculate the new state of the 'Me' cell. This function is executed for every cell in a grid.
int __stdcall __declspec(dllexport) CARule(int Generation,int col,int row,
                                           int NW, int N,  int NE,
                                           int W,  int Me, int E,
                                           int SW, int S,  int SE)
{
  int iSum;
  int newState;

  iSum = (NW != 0) + (N != 0) + (NE != 0) + (W != 0) + (E != 0) + (SW != 0) + (S != 0) + (SE != 0);

  newState = 0;
  if (Me == 0) // was dead
  {
    if (iSum == 3) newState = 1;
  }
  else // was alive
  {
    if ((iSum == 2) || (iSum == 3)) newState = Me + 1; // make it older
  }
  return newState;
}
/////////////////////////////
// Setup the rule.
// The function is called immediatelly after this rule is selected in MCell.
void __stdcall __declspec(dllexport) CASetup(int* RuleType, int* CountOfColors, char* ColorPalette, char* Misc)
{
  *RuleType = 2;        // 1 - 1D, 2 - 2D, 3 - Margolus
  *CountOfColors = 16;  // count of states, here 16: 0..15
  strcpy(ColorPalette, "MCell standard");  // optional color palette specification
  strcpy(Misc, "");     // optional extra parameters, none in this case
}

Note that the folder \MCell\UserDLLs\DLLs\Sources\ contains many examples of rules programmed in several languages. I didn’t succeed yet in programming user DLLs in Visual Basic – I see no way of exporting programmed functions. If anybody knows how to do it I’ll be very thankful for the information.

User DLLs are expected to provide two exported functions: CASetup and CARule (or CASetup and CARule1D in case of 1-D rules). Starting with version 2.50 of MCell user DLLs optionally can contain two more functions: CAPass and CAClose.Since the version 4.20 the next function, CAConfig, is available.

Note: programming user rules in Microsoft Visual C++ got much simpler!

 


CASetup

The procedure is used to initialize the rule. Its parameters return to the program information about the rule type (1- or 2-D), count of states, optional color palette request and optional other parameters.

Syntax:

C / C++:

void __declspec(dllexport) __stdcall CASetup(int* RuleType, int* CountOfColors, char* ColorPalette, char* Misc)

Pascal:

procedure CASetup(var RuleType, CountOfColors: Integer; ColorPalette, Misc: PChar); stdcall;

Parameters:

RuleType integer specifying the rule/neighborhood type. Assign 1 to define the 1-D rule, 2 to define the 2-D rule, and 3 to define a Margolus neighborhood rule.
Example:
C/C++: *RuleType = 2;
Pascal: RuleType := 2;
CountOfColors integer specifying the number of states of the automaton. The number includes also the zero state, so specifying for example 7 results in an automaton with cells in states 0..6.
Example:
C/C++: *CountOfColors = 5;
Pascal: CountOfColors := 5;
ColorPalette pointer to the allocated string buffer of 256 characters. It can be used to specify the color palette that should be automatically loaded when the automaton is selected. One can also ignore this parameter.
Example:
C/C++: strcpy(ColorPalette, ”8 colors”);
Pascal: StrCopy(ColorPalette, '8 colors');
Misc pointer to the allocated string buffer of 256 characters. It can be used for additional initialization of the DLL.

On entry the buffer contains several keywords that can be optionally used for the DLL initialization:
”SIZEX=x SIZEY=y” - the board size formatted as a string
”RULE=” – optional current rule string; used only for configurable DLLs.

On exit the user set into the buffer optional keywords. Current version supports one keyword - "ALLCELLS". If the keyword appears in the returned 'Misc' string, the rule evaluator calls the CARule function for every cell in the board, even if the cell appears to have no chances for changing the state.
Example:
C/C++: strcpy(Misc, ”ALLCELLS”);
Pascal: StrCopy(Misc, 'ALLCELLS');

 


CARule (2-D)

The function is used to calculate and return the new state of the cell given as the ‘Me’ parameter. The resulting new state can be based on the cell’s previous state, and states of neighbours, as in many standard rules, but can also use randomizing, the cycle (generation) number and the cell location on the lattice. One cannot rely on the order in which board cells are evaluated. Currently the board is divided into 10x10 blocks and CARule is called for all cells within the first block, next for all cells within the second block, ..., up to the last block.

Syntax:

C / C++:

int __declspec(dllexport) __stdcall CARule(
  int Generation, int col, int row,
  int NW, int N, int NE,
  int W, int Me, int E,
  int SW, int S, int SE)

Pascal:

function CARule(Generation,col,row,
  NW,N, NE,
  W, Me,E,
  SW,S, SE: Integer): Integer; stdcall;

Parameters:

Generation integer specifying the generation (cycle) count.
col integer specifying the cell column.
row integer specifying the cell row.
Me integer specifying the state of the focused cell. State is in range 0..CountOfColors-1.
NW,N,NE,W,E,SW,S,SE integers specifying the states of the cell neighbours. States are in range 0..CountOfColors-1.

Example:

C/C++:

return (NW + N + NE + W + Me + E + SW + S + SE) % 9;

Pascal:

CARule := (NW + N + NE + W + Me + E + SW + S + SE) mod 9;

 


CARule1D (1-D)

The function is used to calculate and return the new state of the cell given as the ‘Me’ parameter. The resulting new state can be based on the cell’s previous state, and states of left and right neighbours, as in many standard rules, but can also use randomizing, the generation number and the cell location in the row.

C / C++:

int __declspec(dllexport) __stdcall CARule1D(
  int Generation, int col,
  int l10, int l9, int l8, int l7, int l6,
  int l5, int l4, int l3, int l2, int l1,
  int Me,
  int r1, int r2, int r3, int r4, int r5,
  int r6, int r7, int r8, int r9, int r10)

Pascal:

function CARule1D(Generation,col,
l10,l9,l8,l7,l6,l5,l4,l3,l2,l1,
Me,
r1,r2,r3,r4,r5,r6,r7,r8,r9,r10: Integer): Integer; stdcall;

Parameters:

Generation integer specifying the generation (cycle) count.
col integer specifying the cell column (position in the active row).
Me integer specifying the state of the focused cell. State is in range 0..CountOfColors-1.
l10,l9,l8,l7,l6,l5,l4,l3,l2,l1 integers specifying the states of the cell left neighbours. l10 is left-most parameter, l1 is the immediate left neighbour. States are in range 0..CountOfColors-1.
r1,r2,r3,r4,r5,r6,r7,r8,r9,r10 integers specifying the states of the cell right neighbours. r10 is right-most parameter, r1 is the immediate right neighbour. States are in range 0..CountOfColors-1.

Example:

C/C++:

return (l2 + l1 + Me + r1 + r2) % 5;

Pascal:

CARule1D := (l2 + l1 + Me + r1 + r2) mod 5;

 


CARuleMG (Margolus neighborhood)

The procedure is used to determine the new state of four passed cells, building one 2x2 block of the Margolus neighborhood. The resulting new states can be based on the cells' previous states as in many standard rules, but can also use randomizing, the generation number and the cells location in the grid.
The procedure is available since MCell v.4.0.

C / C++:

void __declspec(dllexport) __stdcall CARuleMG(int Generation,
                                     int col, int row,
                                     int* ul, int* ur, int* ll, int* lr)

Pascal:

procedure CARuleMG(Generation,col,row: Integer; var ul, ur, ll, lr: Integer); stdcall;

Parameters:

Generation integer specifying the generation (cycle) count. Generation % 2 tells if the cycle is even or odd.
col integer specifying the ul (upper left) cell column.
row integer specifying the ul (upper left) cell row.
ul upper left cell (passed by reference)
ur upper right cell (passed by reference)
ll lower left cell (passed by reference)
lr lower right cell (passed by reference)

Example:

C/C++:

if (Generation % 2) // odd pass
{
  iTmp = *ul; *ul = *lr; *lr = iTmp;
}
else // even pass
{
  iTmp = *ur; *ur = *ll; *ll = iTmp;
}

Pascal:

if (Generation mod 2) = 1 then // odd pass
begin
  iTmp := ul; ul := lr; lr := iTmp;
end
else // even pass
begin
  iTmp := ur; ur := ll; ll := iTmp;
end;

 


CAPass

If the CAPass procedure is defined in a user DLL, it gets called both before and after each pass (cycle). The procedure is optional, the use of it depends to the user.
The procedure is available since MCell v.2.50.

Syntax:

C / C++:

void __declspec(dllexport) __stdcall CAPass(int Generation, int Population, int PreFlag, char* Misc)

Pascal:

procedure CAPass(Generation, Population, PreFlag: Integer; Misc: PChar); stdcall;

Parameters:

Generation integer specifying the generation (cycle) count.
Population integer specifying the total count of alive (non-zero) cells.
PreFlag integer specifying if the call is done before the pass. PreFlag is 1 before the pass, and 0 after the pass.
Misc pointer to the allocated string buffer of 256 characters. It can be used in next versions for extra communication with DLL. One should ignore this parameter in this version.

 


CAClose

If the CAClose procedure is defined in a user DLL, it gets called before the DLL is disconnected. The procedure is optional; it's usually used to perform the final clean-up as freeing allocated memory.
The procedure is available since MCell v.2.50.

Syntax:

C / C++:

void __declspec(dllexport) __stdcall CAClose(int Generation, int Population)

Pascal:

procedure CAClose(Generation, Population: Integer); stdcall;

Parameters:

Generation integer specifying the generation (cycle) count.
Population integer specifying the total count of alive (non-zero) cells.

CAConfig

Optional CAConfig function allows programming interactively configurable DLLs. When the function is detected in a DLL, MCell’s “Rules setup” offers a new “Configure” button on the UDLL page. It’s up to the DLL author what will happen when the function gets invoked. Usually DLLs will read the rule string from the “Rule” parameter, open a custom dialog for modifying the, and send the modified rule back to the program.

See “\MCell\UserDLLs\DLLs\Sources\D5_WeightedGen” project for an example of a configurable DLL.

Syntax:

C / C++:

void __declspec(dllexport) __stdcall CASetup(
  int* RuleType, int* CountOfColors, char* Rule, char* Misc)

Pascal:

procedure CASetup(var RuleType, CountOfColors: Integer;
  Rule, Misc: PChar); stdcall;

Parameters:

RuleType parameter currently ignored;
CountOfColors parameter currently ignored;
Rule pointer to the allocated string buffer of 256 characters.
On entry the buffer contains the active rule string.
On exit the buffer contains the modified rule string that should be activated in the program.
Example:
C/C++: strcpy(Rule, ”c=3,r=1”);
Pascal: StrCopy(Rule, 'c=3,r=1');
Misc pointer to the allocated string buffer of 256 characters. Parameter currently ignored;

Step-by-step procedure of creating a new rule in MSVC 6.0

Note!
This simplified method of creating user DLLs in MSVC works in MCell starting with 2.60.0.399. Older versions require DLLs created with a use of a DEF file.

  1. Select File/New, then Project/Win32 Dynamic-Link Library.
  2. Enter the project name, specify its location, press [Ok].
  3. Select "A simple DLL project", press [Finish].
  4. Edit your main source module (<project>.cpp file): add functions CASetup and CARule (or CARule1D/CARuleMG). The easiest way is to copy them from another similar rule.
  5. Fill the function CASetup with the rule initialization and CARule with your rule definition.
  6. Select the Win32 Release build version.
  7. Build the DLL (F7).
  8. Copy your DLL from your project's \Release\ subfolder to MCell\UserDLLs\DLLs\ folder. DLL is ready for testing.

 


Step-by-step procedure of creating a new rule in Delphi 4.0/5.0

  1. Create a new folder for your rule.
  2. Open one of sample templates provided in the \MCell\UserDLLs\DLLs\Sources\ folder.
    Use D5_Template2D when creating a 2-D rule,  D5_Template1D when creating a 1-D rule and D5_TemplateMG when creating a Margolus rule.
  3. Select File/Save project as...
  4. Save it with any name in the folder created in step 1.
  5. Edit the source module - change the contents of CASetup and CARule (or CARule1D) functions.
  6. Select Project/Build to compile your DLL.
  7. Copy your DLL from your folder to MCell\UserDLLs\DLLs\ folder. DLL is ready for testing.

 


Step-by-step procedure of creating a new rule in Borland C++ Builder 3.0/4.0

Big thanks to Brian Behlendorf for writing Borland C and Borland C++ Builder DLL templates and making this recipe!

  1. Create a new folder for your rule.
  2. Open one of templates provided in the \MCell\UserDLLs\DLLs\Sources\BCB3_Template folder. Use BCB3_2D when creating a 2-D rule, or BCB3_1D when creating a 1-D rule.
  3. Select File/Save project as...
  4. Save it with any name in the folder created in step 1.
  5. Edit the source module - change the contents of CASetup and CARule (or CARule1D) functions.
  6. Select Project/Build to compile your DLL.
  7. Copy your DLL from your folder to MCell\UserDLLs\DLLs\ folder. DLL is ready for testing.

Note that such created DLLs are not stand alone - they require Borland runtime libraries. To create DLLs that will work on any computer, perform two additional steps:

  1. Under the linker tab, uncheck use dynamic RTL.
  2. Under the packages tab, uncheck build with runtime packages.

 


Webmaster: Mirek Wojtowicz

globe http://www.mirekw.com

MCell mirrors:
globe USA  http://psoup.math.wisc.edu/mcell/
globe Europe  http://www.mirwoj.opus.chelm.pl

Last update: 10 Mar 2002