Code in Processing, its javascript variant p5

var blockSize = 10;
var grid = [];
var cells = [];

var NONE = 0;
var YIN = 1;
var YANG = 2;

var MINUS = 1;
var ZERO = 2;
var PLUS = 5;

//neighbour: none,  yin,   yang
var game = [
  [ZERO, MINUS, MINUS],
  [MINUS, PLUS, ZERO], // yin cells
  [MINUS, ZERO, PLUS] // yang cells
];


function setup() {
  var xGrid = round(0.9 * windowWidth / blockSize);
  var yGrid = round(0.9 * windowHeight / blockSize);
  var canvas = createCanvas(xGrid * blockSize, yGrid * blockSize);

  background(255);
  colorMode(HSB);
  noStroke();

  scale(blockSize);

  makeGrid(xGrid, yGrid);
  setNeighbors();
  drawAll();
}

function makeGrid(xGrid, yGrid) {
  var nothing = new Compound(NONE);
  cells.push(nothing);

  for (var x = 0; x < xGrid; x++) {
    grid[x] = [];
    for (var y = 0; y < yGrid; y++) {
      comp = nothing; // most of the space is empty
      if (0.25 * xGrid < x && x < 0.75 * xGrid && 0.25 * yGrid < y && y < 0.75 * yGrid) {
        if (random(30) < 1) {
          if (random(2) < 1) comp = new Compound(YIN);
          else comp = new Compound(YANG);
          cells.push(comp);
        }
      }
      grid[x][y] = new Atom(x, y, comp);
    }
  }
}

function setNeighbors() {
  for (var x = 0; x < grid.length; x++) {
    for (var y = 0; y < grid[0].length; y++) {
      grid[x][y].setNeighbors();
    }
  }
}

function drawAll() {
  for (var x = 0; x < grid.length; x++) {
    for (var y = 0; y < grid[0].length; y++) {
      grid[x][y].draw();
    }
  }
}

function draw() {
  scale(blockSize);
  for (var i = 0; i < grid.length * grid[0].length; i++) update();
}

function update() {
  var atom = random(random(grid));

  var fitness = 0;
  for (var i = 0; i < atom.neighbors.length; i++) {
    fitness += game[atom.cellType()][atom.neighbors[i].cellType()] / atom.neighbors.length; // calculate fitness
  }

  if (fitness * atom.cellDensity() > random(MINUS, PLUS)) { // if fit
    random(atom.neighbors).change(atom.cell); // assimilate neighbour
  }
}

function Atom(X, Y, cel) {
  this.x = X;
  this.y = Y;
  this.cell = cel;
  this.neighbors = [];

  this.setNeighbors = function() {
    if (this.x > 0) this.neighbors.push(grid[this.x - 1][this.y]); // left
    if (this.y > 0) this.neighbors.push(grid[this.x][this.y - 1]); // down
    if (this.y < grid[0].length - 1) this.neighbors.push(grid[this.x][this.y + 1]); // up
    if (this.x < grid.length - 1) this.neighbors.push(grid[this.x + 1][this.y]); // right
  };

  this.cellType = function() {
    return this.cell.type;
  }
  this.cellDensity = function() {
    return this.cell.density();
  }
  this.draw = function() {
    fill(this.cell.colour);
    rect(this.x, this.y, 1, 1);
  }
  this.change = function(cel) {
    this.cell.shrink();
    this.cell = cel;
    this.cell.stretch();
    this.draw();
  }
}

function Compound(Type) {
  this.cellSize = 20;
  this.type = Type;
  this.colour = color(255);
  this.atoms = 0;
  var vary = random(-25, 25);
  if (YIN == this.type) this.colour = color(200, 100, 75 + vary);
  if (YANG == this.type) this.colour = color(300, 100, 75 + vary);

  this.cellType = function() {
    return this.type;
  }
  this.stretch = function() {
    this.atoms++;
  }
  this.shrink = function() {
    this.atoms--;
  }
  this.density = function() {
    if (NONE == this.type) return 1;
    return this.cellSize / this.atoms;
  }
}