class being {
// represents a single cell, which is a member of a species.
float ag; // speed at which species spreads into neighbouring cells 0-1.0
int type;
public being(int _type,float _ag) {
type=_type;
ag=_ag;
}
public void debug() {
print ("Species=("+type+")\n");
}
}
// simple crystallization
// by Steven Kay
// We have a number of "species", each of different colour
// The grid (world) starts with a random scattering of beings from each species
// These act as 'nucleation sites'.
// Beings can spread into neighbouring empty squares, at a speed defined by their
// 'agressiveness' setting.
// Currently, beings can only spread into empty cells. A more complex implementation
// would apply rules to allow cells to 'fight' neighbouring cells and move into the 'defeated' cell.
world w;
int RANDOM=0;
int SPARSE=1;
int BEHAVIOUR=SPARSE;
void setup() {
w=new world(BEHAVIOUR);
size(400,400);
frameRate(16);
}
void mousePressed() {
// click to start over
w=new world(BEHAVIOUR);
}
void keyPressed() {
// change behaviour
if (key=='g' || key=='G') {
w.toggleGrid();
return;
}
if (key=='s' || key=='S') BEHAVIOUR=SPARSE;
if (key=='r' || key=='R') BEHAVIOUR=RANDOM;
w=new world(BEHAVIOUR);
}
void draw() {
background(0);
w.draw();
w.doGen();
}
class species {
// represents a species
float agressiveness; // speed at which species spreads into neighbouring cells 0-1.0
color col; // color
int type; // unique number
public species(int _type) {
agressiveness=random(0,1.0);
col=color(random(120,255),random(0,255),random(120,255));
type=_type;
}
public void debug() {
print ("Species (Ag="+agressiveness+", Ty="+type+")\n");
}
public being spawn() {
// give birth to a new member of this species
return new being(this.type,this.agressiveness);
}
}
class world {
// represents the game world, a grid
// cells may be instances of being, or null (empty)
int NUMBER_SPECIES=int(random(2,12));
int SIZE=100;
being[][] grid;
being[][] newgrid;
ArrayList allSpecies;
int mode;
boolean showGrid=false;
public world(int behaviour) {
this.mode=behaviour;
allSpecies=new ArrayList();
for (int i=0;i<=NUMBER_SPECIES;i++) {
allSpecies.add(new species(i));
species s=(species)allSpecies.get(i);
s.debug();
}
grid=new being[SIZE][SIZE];
newgrid=new being[SIZE][SIZE];
// use ONE of the following.
// RANDOM means each species can have more than one staring point
// SPARSE means each species has only one starting point
if (mode==RANDOM) populateRandom();
if (mode==SPARSE) populateSparse();
}
public void setMode(int mode) {
this.mode=mode;
}
public void toggleGrid() {
// turn grid on/off
this.showGrid=!this.showGrid;
}
public void populateRandom() {
// one in a hundred cells are set to a random species
for (int row=0;row<SIZE;row++) {
for (int col=0;col<SIZE;col++) {
// populate with a member of a randomly picked species
if (random(0,100)>99) {
species s=(species)allSpecies.get((int)random(0,allSpecies.size()-1));
grid[row][col]=s.spawn();
}
}
}
}
public void populateSparse() {
// each species is given a single unoccupied starting point
for (int s=0;s<NUMBER_SPECIES;s++) {
int row=int(random(0,SIZE-1));
int col=int(random(0,SIZE-1));
while (grid[row][col]!=null) {
// ensure a unique, unoccupied cell for each species
row=int(random(0,SIZE-1));
col=int(random(0,SIZE-1));
}
species sp=(species)allSpecies.get(s);
grid[row][col]=sp.spawn();
}
}
public void doGen() {
// create next generation
for (int row=0;row<SIZE;row++) {
for (int col=0;col<SIZE;col++) {
being b=grid[row][col];
if (b==null) continue; // skip null cells
newgrid[row][col]=grid[row][col]; // default-cell copied to next gen.
int s=b.type;
species sp=(species)allSpecies.get(s);
int up=(row==0?SIZE-1:row-1);
int down=(row==SIZE-1?0:row+1);
int left=(col==0?SIZE-1:col-1);
int right=(col==SIZE-1?0:col+1);
int newrow=0,newcol=0;
if (random(0,1.0)>b.ag) {
// if cell decides to move..
switch ((int)random(0,8)) {
case(0): newrow=up;newcol=left;break;
case(1): newrow=up;newcol=col;break;
case(2): newrow=up;newcol=right;break;
case(3): newrow=row;newcol=left;break;
case(4): newrow=row;newcol=right;break;
case(5): newrow=down;newcol=left;break;
case(6): newrow=down;newcol=col;break;
case(7): newrow=down;newcol=right;break;
default: print ("NO!");break;
}
// decide what to do.. move into empty square..
if (grid[newrow][newcol]==null) {
// empty cell, so... spawn a new copy of this species
newgrid[newrow][newcol]=sp.spawn();
} else {
// non-empty cell.
// in a future version.. make the cells fight!!
;
}
}
}
}
grid=newgrid; // start from new generation
}
public void draw() {
// draw world
stroke(0);
if (!this.showGrid) noStroke();
for (int row=0;row<SIZE;row++) {
for (int col=0;col<SIZE;col++) {
being b=grid[row][col];
if (b!=null) {
int s=b.type;
species sp=(species)allSpecies.get(s);
fill (sp.col);
rect(col*4,row*4,4,4);
}
}
}
}
}