Week 6 - Cellular Automata and the Game of Life

Date: 2025-03-05

Today

A-life

New media art self-consciously reworks technology into culture, and rereads technology as culture. What’s more, it does so in a concrete, applied way; it manipulates the technology itself, with a nonindustrial latitude that admits misapplication and adaptation, rewiring and hacking, pseudofunctionality and accident. p.5, Metacreation

A-life begins with a notion of life that is wholly materialistic, involving no soul, vital force, or essence. In the words of the convenor of the first artificial life workshop, Christopher Langton, ‘Living organisms are nothing more that complex biochemical machines.’ Langton contends that rather than being any special substance or force, life is ‘a property of the organization of matter.’ Further, this organization is not simply a complex structure but a dynamic structure, a system active in real time: for a-life, life is most importantly manifest in behavior. p.7, Metacreation

Tenets of this approach:

Systems:

We are no longer creating a work, we are creating creation…We are able to bring forth…results…which go beyond the intentions of their originators, and this in infinite number. – Nicholas Schöffer p.16, Metacreation

Inventing the Game of Life

Stephen Hawkings The Meaning of Life (John Conway’s Game of Life segment)

Inventing Game of Life (John Conway) - Numberphile

Cellular Automata in p5.js

from p5.js examples - Game of Life

Cellular Automata in Minecraft

Multiple Neighborhood Cellular Automata

More explorations with Multiple Neighborhoods Cellular Automata by softology

Procedural Level Design in Brogue and Beyond

Resources

Forces

Goal: Have a number of objects move independently and respond to environmental forces.

A force is a vector that causes an object with mass to accelerate.

Newton’s 3 Laws of Motion

  1. An object at rest remains at rest or an object in motion stays in motion at a constant velocity (speed and direction), unless acted upon by a force.
  2. Force equals mass times acceleration.
  3. For every action there is an equal and opposite reaction. Forces occur in pairs, in equal strength, in opposite directions.

Mass - measure of matter in an object, (in kilograms)
Weight - the force of gravity on an object (in newtons)
density - mass per unit (such as grams per centimeter)

In our sketches, the acceleration of an object is its force.

Pseudocode - concept

//NOTE: this is PSEUDOCODE to understand a concept!

class Mover {
  constructor(){
    vector location;
    vector velocity;
    vector acceleration;
  }
}
//PSEUDOCODE
// example applying methods

mover.applyForce(wind);
mover.applyForce(gravity);

....

//example method code inside a mover class

applyForce(vector force) {
  acceleration = force;
}

Note: the force really needs to reflect the total of all of the forces acting together: wind, gravity, and anything else. This could change from moment to moment, such as changing wind, so we need to recalculate every draw loop. We can do this by multiplying the acceleration by 0 at the end of a loop.

function update() {
    velocity.add(acceleration);
    location.add(velocity);
    acceleration.mult(0);
 }

Now, let’s work in actual Javascript/p5.js. Let’s create a mover, and apply a force to it.

//modified from Daniel Shiffman's The Nature of Code

let m;

function setup() {
  createCanvas(640, 360);
  m = new Mover();
}

function draw() {
  background(50);

  //change its x value to move to the right
  let wind = createVector(0.01, 0); 
  m.applyForce(wind);

  m.update(); //change position
  m.display(); //draw to screen
  m.checkEdges(); //did we run off screen?
}

Now that we have the basic code mocked out, we need to build the actual Mover class.

class Mover {
  constructor() {
    this.mass = 1;
    this.position = createVector(30, 30);
    this.velocity = createVector(0, 0); //starts at 0 until applied
    this.acceleration = createVector(0, 0); //starts at 0 until applied
  }

  applyForce(force) {
    var f = p5.Vector.div(force, this.mass); [derived](//derived) from Newton's Second Law
    this.acceleration.add(f); //add all the forces together (wind, gravity, etc)
  }

  update() {
    this.velocity.add(this.acceleration);  //acceleration is added to velocity
    this.position.add(this.velocity);  //velocity is added to position to get the next position
    this.acceleration.mult(0); //we reset the force to 0 at end
  }

  display() {
    stroke(0);
    strokeWeight(2);
    fill(255, 127);
    ellipse(this.position.x, this.position.y, 48, 48);
  }

  checkEdges() {
    if (this.position.x > width) {
      this.position.x = width;
      this.velocity.x *= -1;
    } else if (this.position.x < 0) {
      this.velocity.x *= -1;
      this.position.x = 0;
    }
    if (this.position.y > height) {
      this.velocity.y *= -1;
      this.position.y = height;
    }
  }

}

Our full code example.

At this point, we have a single mover. We can create an array of movers, each with their own starting position, and forces acting on them.

//modified from Dan Shiffman Nature of Code
let movers = [];

function setup() {
  createCanvas(640, 360);
  for (let i = 0; i < 20; i++) { //initializing an array of 20 movers
    movers[i] = new Mover(random(0.1, 5), 0, 0);
  }
}

function draw() {
  background(255);

  for (let i = 0; i < movers.length; i++) { //this runs in a loop, so that it affects all movers individually
    let wind = createVector(0.01, 0);
    let gravity = createVector(0, 0.1);
    movers[i].applyForce(wind);
    movers[i].applyForce(gravity);
    movers[i].update();
    movers[i].display();
    movers[i].checkEdges();
  }
}

Notice the smaller movers are faster. Acceleration is force divided by mass, so larger masses have smaller accelerations.

An example with mousePressed to create a wind force on 2 movers.

// The Nature of Code
let moverA;
let moverB;

function setup() {
  createCanvas(640, 360);
  // A large Mover on the left side of the window
  moverA = new Mover(200, 30, 10);
  // A smaller Mover on the right side of the window
  moverB = new Mover(440, 30, 2);
  createP('Click mouse to apply wind force.');
}

function draw() {
  background(51);

  let gravity = createVector(0, 0.1);

  let gravityA = p5.Vector.mult(gravity, moverA.mass);
  moverA.applyForce(gravityA);

  let gravityB = p5.Vector.mult(gravity, moverB.mass);
  moverB.applyForce(gravityB);

  if (mouseIsPressed) {
    let wind = createVector(0.1, 0);
    moverA.applyForce(wind);
    moverB.applyForce(wind);
  }

  moverA.update();
  moverA.display();
  moverA.checkEdges();

  moverB.update();
  moverB.display();
  moverB.checkEdges();
}

code example

array of movers with forces - code example

Ecosystem Project