cellauto.js


            

About

cellauto.js is a library for creating cellular automata simulations in Javascript. The library is tiny and is pure Javascript, requiring no third party code to run in your browser. The project is open-source and licensed under MIT. Some of the API ideas were inspired by the excellent project, terra.

Usage

Getting Started

Creating the world to run your simulation is simple.
var world = new CAWorld({
    width: 96,
    height: 64
});
                

Defining a cell

Now you need to define a cell that will live in your world. Lets start with the classic cellular automata example, Conway's Game of Life.
world.registerCellType('living', {
    getColor: function () {
        return this.alive ? '68, 36, 52, 1' : '255, 255, 255, 1';
    },
    process: function (neighbors) {
        var surrounding = this.countSurroundingCellsWithValue(neighbors, 'wasAlive');
        this.alive = surrounding === 3 || surrounding === 2 && this.alive;
    },
    reset: function () {
        this.wasAlive = this.alive;
    }
}, function () {
    //init
    this.alive = Math.random() > 0.5;
});
                
In the above example, a cell that has 2 living cells surrounding it will survive. If 3 living cells surround surround the cell, it can come back from the dead.

Here are some interesting functions from the above example:
  • process

    This function is called every step of the simulation and is passed an array of neighbors to this cell.

  • reset

    This function is called at the beginning of each step of the simulation to prepare the cell for the upcoming step.

  • getColor

    This is our own function for determining what color the cell will be. It will be used in our display loop, which is not part of the engine.


You can also see an init function was passed at the end of the definition. It is used to initialize the cell when the simulation starts. In this case it determines if each cell is alive or dead to start the simulation.

Adding cells to the world

Cells are added to the world in the initialization step.
world.initialize([
    { name: 'living', distribution: 100 }
]);

                
In this example, cells of the type "living" will be added to the world and assigned 100% of the cells. If we wanted the world to begin with more types of cells, we could initialize like this.
world.initialize([
    { name: 'water', distribution: 40 },
    { name: 'rock', distribution: 60 }
]);
                

Other interesting functions

  • step

    This is used to make the simulation run one loop. Typically you would run step from setInterval or requestAnimationFrame.

  • countSurroundingCellsWithValue

    Returns a count of members of the given cell array that contain the given propery. This is useful in many cellular automata simulations.

process: function (neighbors) {
    var surrounding = this.countSurroundingCellsWithValue(neighbors, 'wasOpen');
    this.open = (this.wasOpen && surrounding >= 4) || surrounding >= 6;
}
                
  • delay

    Pass a number of steps and a callback function. The callback will be called after the given number of steps with the cell passed as an argugment. See the "trees" example.

process: function (neighbors) {
    this.delay(10, function(cell) {
        cell.doSomething();
    });
}
                
  • createGridFromValues

    Creates a grid of values which can be used as input for a new world. In this way, we can build our simulated world in several iterations. See the "cavesWithWater" example.

var grid = world.createGridFromValues([
        { cellType: 'wall', hasProperty: 'open', value: 0 }
    ], 1);
                
  • initializeFromGrid

    Accepts a grid generated with "createGridFromValues" and a list of what values mean which cellTypes in this new simulated world.

world.initializeFromGrid([
    { name: 'rock', gridValue: 1 },
    { name: 'water', gridValue: 0 }
], grid);

Display

There is no display code included in the library. How you display each cell is up to you. You can iterate the value of each cell in a simple loop.
for (var y=0; y<world.height; y++) {
    for (var x=0; x<world.width; x++) {
        var cell = world.grid[y][x];
        // TODO: awesome rendering of the cell
    }
}