This shows an early version of my Wu Xing-inspired cellular automata, taking the form of a Reaction-Diffusion model. This isn’t as commented and a little more obscure than the DLA code, but you should be able to copy/paste the code into processing and get a simple reaction/diffusion cellular automata in Processing:
class WuXingCell
{
float[] element;
};
int worldScale = 8;
int worldSize = 64;
int mode = 1;
WuXingCell[][] world;
WuXingCell[][] nextWorld;
color[] WuXingColor;
float waterLevel = .25;
int dayBand = 0;
float natLog = 0.36787944118;
float eLog = 2.7182818284;
float growRate = .2;
float destroyRate = .11;
float insultRate = .1;
float growThresh = .1;
float destroyThresh = .2;
float insultThresh = .4;
float[] elementFlow; //how much is moved when it erodes
float[] elementStrength; //when element decides to erode
float[] elementDistScale; //distance from strongest points
float[] elementReactivity;
int dominantElement = 0;
float seaLevel = 0;
int water = 0; //we do this so the code is more readable, also showing the cyclical order
int wood = 1;
int fire = 2;
int earth = 3;
int metal = 4;
int mouseElement = 0;
float[] alchemyAmounts;
float[] alchemyAdditives;
boolean elementPoles = true;
boolean react = false;
void updateWorld()
{
for (int i = 0; i < worldSize; i++)
{
for (int j = 0; j < worldSize; j++)
{
for (int k = 0; k < 5; k++)
{
world[i][j].element[k] = nextWorld[i][j].element[k];
//print(“.”);
}
}
}
}
void ProcessWorld()
{
for (int i = 0; i < worldSize; i++)
{
for (int j = 0; j < worldSize; j++)
{
for (int k = 0; k < 5; k++) //imagine 5 buckets in each cell, we look at them and their neighbors…
{
alchemyAmounts[k] = world[i][j].element[k];
for (int adjI = -1; adjI < 2; adjI++)
{
for (int adjJ = -1; adjJ < 2; adjJ++)
{
alchemyAmounts[k] += (world[LoopVar(i + adjI)][LoopVar(j + adjJ)].element[k]) * (0.125); //0.125 = 1/8th, averaging the 8 adjacent cells
}
}
}
ProcessAlchemy(); //now that we have the amoutns, process what they do…
for (int k = 0; k < 5; k++) //a little bit of hacky averaging, and updating the old board
{
alchemyAmounts[k]/=2;
nextWorld[i][j].element[k] = alchemyAmounts[k];
}
}
}
}
void ProcessAlchemy()
{
float[] newAlchemy = new float[5];
float[] fractionOf = new float[5];
float totalAmount = 0;
for (int k = 0; k < 5; k++)
{
newAlchemy[k] = alchemyAmounts[k];
totalAmount += alchemyAmounts[k];
}
for (int k = 0; k < 5; k++)
{
fractionOf[k] = totalAmount/alchemyAmounts[k];
}
int grandParent, parent, child, grandChild;
for (int k = 0; k < 5; k++) //figure out what elements are “parent”, “child” etc. relative to the one you’re on
{
grandParent = 6;
parent = 6;
child = 6;
grandChild = 6;
if (k == water)
{
grandParent = earth;
parent = metal;
child = wood;
grandChild = fire;
}
if (k == wood)
{
grandParent = metal;
parent = water;
child = fire;
grandChild = earth;
}
if (k == fire)
{
grandParent = water;
parent = wood;
child = earth;
grandChild = metal;
}
if (k == earth)
{
grandParent = wood;
parent = fire;
child = metal;
grandChild = water;
}
if (k == metal)
{
grandParent = fire;
parent = earth;
child = water;
grandChild = wood;
}
elementReactivity[k] = 1;// *= 1.5; //how much do we react the elements (scalar, multply by this amount)
//natLog = .3;
newAlchemy[k] += (alchemyAmounts[parent] * natLog);
newAlchemy[k] -= (alchemyAmounts[child] * natLog);
if (alchemyAmounts[grandParent] > alchemyAmounts[k]) //grandfather destroys…
{
newAlchemy[k] -= (alchemyAmounts[grandParent] * natLog);
}
// else //…or it’s too big and we’re insulted
if (alchemyAmounts[grandChild] > alchemyAmounts[k])// //grandfather destroys…
{
newAlchemy[k] -= (alchemyAmounts[grandParent] * natLog);
}
if ( newAlchemy[k] > 1.0) newAlchemy[k] = 1.0;
if ( newAlchemy[k] < 0.0) newAlchemy[k] = 0.0;
}
for (int k = 0; k < 5; k++)
{
alchemyAmounts[k] = newAlchemy[k];
}
}
void draw()
{
dominantElement += 1;
if (dominantElement >= 5) dominantElement = 0;
ProcessWorld();
ProcessAlchemy();
updateWorld();
background(0);
color pixelColor = color(0,0,0);
float finRed, finGreen, finBlue;
if(keyPressed) {
if (key == ’0′) {
alchemyAdditives[water] += .1;
//mouseElement = water;
}
if (key == ’1′) {
alchemyAdditives[wood] += .1;
//mouseElement = wood;
}
if (key == ’2′) {
alchemyAdditives[fire] += .1;
//mouseElement = fire;
}
if (key == ’3′) {
alchemyAdditives[earth] += .1;
//mouseElement = earth;
}
if (key == ’4′) {
alchemyAdditives[metal] += .1;
//mouseElement = metal;
}
if (key == ‘r’) {
for (int k = 0; k < 5; k++)
{
alchemyAmounts[k]= random(0,1.0);
}
}
if (key == ‘e’) {
for (int k = 0; k < 5; k++)
{
alchemyAmounts[k]= 0;
alchemyAdditives[k] = 0;
}
//mouseElement = water;
}
if (key == ‘t’) {
for (int k = 0; k < 5; k++)
{
alchemyAmounts[k] += alchemyAdditives[k];
alchemyAdditives[k] = 0;
}
//mouseElement = water;
}
}
float maxElement = 0;
int theMaxElement = 0;
int numElements = 0;
for (int i = 0; i < worldSize; i++) //do a bunch of comparisons to get colors, but we’re basically looping through the board and drawing
{
for (int j = 0; j < worldSize; j++)
{
finRed = 0;
finGreen = 0;
finBlue = 0;
maxElement = 0;
theMaxElement = 0;
numElements = 0;
for (int k = 0; k < 5; k++)
{
if (world[i][j].element[k] > maxElement)
{
maxElement = world[i][j].element[k];
theMaxElement = k;
}
if (world[i][j].element[k] > 0)
{
numElements++;
}
finRed += (red(WuXingColor[k]) * world[i][j].element[k]);
finGreen += (green(WuXingColor[k]) * world[i][j].element[k]);
finBlue += (blue(WuXingColor[k]) * world[i][j].element[k]);
}
finRed /= numElements;
finGreen /= numElements;
finBlue /= numElements;
if (((world[i][j].element[earth] + world[i][j].element[metal])/2) <= seaLevel)
{
pixelColor = color(0,0,seaLevel);
}
else
{
pixelColor = WuXingColor[theMaxElement];//color(finRed,finGreen,finBlue);
//pixelColor *= world[i][j].element[theMaxElement];
//pixelColor = color(world[i][j].element[3],world[i][j].element[2],0);
switch(theMaxElement)
{
case 0:
pixelColor = color(0,world[i][j].element[0],world[i][j].element[0]);
break;
case 1:
pixelColor = color(0,world[i][j].element[1],0);
break;
case 2:
pixelColor = color(1.0,0,0);
break;
case 3:
pixelColor = color(world[i][j].element[3],world[i][j].element[2],0);
break;
case 4:
pixelColor = color(world[i][j].element[3],world[i][j].element[3],world[i][j].element[2]);
break;
}
pixelColor = color(finRed,finGreen,finBlue);//color(finRed,finGreen,finBlue);
}
if (((world[i][j].element[earth] + world[i][j].element[earth])/2) > seaLevel)
{
//pixelColor = color(0,(world[i][j].element[earth] + world[i][j].element[earth])/2,0);
}
else
{
//pixelColor = color(0,(world[i][j].element[earth] + world[i][j].element[earth])/2,.75);
}
if (((world[i][j].element[earth] + world[i][j].element[metal])/2) <= seaLevel)
{
//pixelColor = color(0,0,seaLevel);
}
else
{
//pixelColor = color(finRed,finGreen,finBlue);
}
// if (elementVision != 5) pixelColor = color(0,world[i][j].element[elementVision],0);
//pixelColor = color(0,world[i][j].element[metal],0);
// pixelColor = color(0,0, world[i][j].element[0] );
//pixelColor = color (world[i][j].element[0],0,0);
//set (i * 2,j * 2,pixelColor);
//set (i * 1,j * 1,pixelColor);
fill(pixelColor);
rect(i * worldScale, j * worldScale, (i * worldScale) + (worldScale – 1), (j * worldScale) + (worldScale – 1));
}
}
}
float Clamp(float tempVar, float low, float high)
{
if (tempVar < low) tempVar = low;
if (tempVar > high) tempVar = high;
return tempVar;
}
int LoopVar(int theVar) //clamps var to make sure we loop, assume error is never more than one or two “off map”
{
if (theVar < 0)
{
theVar += worldSize;
}
if (theVar >= worldSize)
{
theVar -= worldSize;
}
return theVar;
}
void setup()
{
//worldScale = 2;
frameRate(24);
colorMode(RGB, 1.0);
size(worldSize * worldScale,worldSize * worldScale);
world = new WuXingCell[worldSize][worldSize];
nextWorld = new WuXingCell[worldSize][worldSize];
//growRate = .2;
//destroyRate = .2;
//insultRate = .1;
WuXingColor = new color[5];
WuXingColor[water] = color(0,0,1);//water
WuXingColor[wood] = color(0,1,0);//wood
WuXingColor[fire] = color(1,0,0);//fire
WuXingColor[earth] = color(1,1,0);//earth
WuXingColor[metal] = color(1,1,1);//metal
elementFlow = new float[5];
elementStrength = new float[5];
elementDistScale = new float[5];
elementReactivity = new float[5];
alchemyAmounts = new float[5];
alchemyAdditives = new float[5];
for (int k = 0; k < 5; k++)
{
elementFlow[k] = 0;
elementStrength[k] = 0;
elementDistScale[k] = 1;
elementReactivity[k] = 1;
alchemyAmounts[k] = 0.5;//random(0,1.0);
alchemyAdditives[k] = 0;
}
elementFlow[earth] = .05; //earth
elementStrength[earth] = .1;
//elementFlow[metal] = .25; //metal
//elementStrength[metal] = .3;
elementFlow[metal] = .4; //metal
elementStrength[metal] = .5;
elementFlow[fire] = .21;
elementStrength[fire] = .11;
for (int i = 0; i < worldSize; i++)
{
for (int j = 0; j < worldSize; j++)
{
world[i][j] = new WuXingCell();
world[i][j].element = new float[5];
for (int k = 0; k < 5; k++)
{
world[i][j].element[k] = random(.1,.9);//.25 + random(0,.5);//random(0.0,1.0);//.5;
// world[i][j].element[k] = 0.5;
//world[i][j].element[k]/=255;
}
//world[i][j].element[0] = .6;
//world[i][j].element[0] = .2;
nextWorld[i][j] = new WuXingCell();
nextWorld[i][j].element = new float[5];
for (int k = 0; k < 5; k++)
{
nextWorld[i][j].element[k] = 1;//random(0,1);
}
//print(” “);
//print(world[i][j].terraHeight);
}
}
//ProcessHeat();
}

Thanks a lot for posting this, but unfortunately we cannot copy the code for some reason.