var canvas = createCanvas(windowWidth, windowHeight);
border = width * height * 0.00002;
strokeWeight(2 * border);
rect(0, 0, width, height);
var res = parseInt(random(100) < 50 ? random(500, 8000) : random(8000, 100000));
drawer = new Wolframdrawer(new Grid({
if (drawer.grid.size() < 8000) {
drawer.initDrawingStack();
function mousePressed() {
function Wolframdrawer(grid) {
this.wolf = new Wolfram(this.grid.columns, this.grid.rows);
this.initDrawingStack = function() {
function Child(i, wolf) {
this.perform = function() {
this.wolf.children[this.i].draw();
this.hello = function() {
function Parent(wolf, drawBackground) {
this.drawBackground = drawBackground;
this.perform = function() {
this.wolf.draw(this.drawBackground);
this.hello = function() {
if (this.children.length > 0) {
for (var i = 0; i < this.children.length; i++) {
var c = new Child(i, this);
this.drawingStack.push(c);
if (this.children.length > 0 && this.keepWhite || this.children.length == 0) {
var w = new Parent(this, false);
this.drawingStack.push(w);
this.drawingStack.reverse();
var p = new Parent(this);
this.drawingStack.push(p);
if (this.children.length > 0) {
this.drawingSpeed = floor(this.drawingStack.length / 20.0);
var childRes = this.children[0].grid.rows;
if (childRes >= 35 && childRes < 50) {
this.drawingSpeed = this.drawingSpeed > 10 ? 10 : this.drawingSpeed;
} else if (childRes >= 50 && childRes < 80) {
this.drawingSpeed = this.drawingSpeed > 5 ? 5 : this.drawingSpeed;
} else if (childRes >= 80 && childRes < 120) {
this.drawingSpeed = this.drawingSpeed > 3 ? 3 : this.drawingSpeed;
} else if (childRes >= 120) {
if (this.drawingSpeed < 1) {
} else if (this.drawingSpeed > 100) {
this.stackDraw = function() {
for (var i = 0; i < this.drawingSpeed; i++) {
var ds = this.drawingStack.pop();
this.initChildren = function() {
this.keepWhite = Math.random() * 100 < 50;
this.childProp = parseFloat(Math.random() * 80);
var overlap = Math.random() * 100 < 30 ? 1 : (2 * parseInt(1 + Math.random() * 4));
var childRes = parseInt(5 + Math.random() * ((overlap * this.grid.cellWidth()) - 5));
for (var i = 0; i < this.grid.size(); i++) {
var row = this.grid.getRow(i);
var column = this.grid.getColumn(i);
var state = this.wolf.state(column, row);
var x = this.grid.getX(i);
var y = this.grid.getY(i);
var w = this.grid.cellWidth();
var h = this.grid.cellHeight();
if (state == 0 && Math.random() * 100 < this.childProp) {
var child = new Wolframdrawer(new Grid({
size: childRes * childRes
this.children.push(child);
this.draw = function(drawBackground) {
if (drawBackground == undefined) {
rect(this.grid.x, this.grid.y, this.grid.w, this.grid.h);
for (var i = 0; i < this.grid.size(); i++) {
var row = this.grid.getRow(i);
var column = this.grid.getColumn(i);
var state = this.wolf.state(column, row);
var x = this.grid.getX(i);
var y = this.grid.getY(i);
var w = this.grid.cellWidth();
var h = this.grid.cellHeight();
rect(x - w / 2, y - h / 2, w, h);
if (options.size != undefined) {
var wh = this.w > this.h;
var aspectRatio = wh ? this.w / this.h : this.h / this.w;
numX = numY = parseInt(Math.sqrt(options.size * aspectRatio));
numX = parseInt(Math.sqrt(options.size * aspectRatio));
numY = parseInt(options.size / parseFloat(numX));
numY = parseInt(Math.sqrt(options.size * aspectRatio));
numX = parseInt(options.size / parseFloat(numY));
this.rows = options.rows;
this.columns = options.columns;
return this.rows * this.columns;
this.getX = function(index) {
var j = index % this.columns;
return this.x + (j + 0.5) * this.w / this.columns;
this.getY = function(index) {
var i = (index - index % this.columns) / this.columns;
return this.y + (i + 0.5) * this.h / this.rows;
this.cellWidth = function() {
return this.w / this.columns;
this.cellHeight = function() {
return this.h / this.rows;
this.getRow = function(index) {
return (index - index % this.columns) / this.columns;
this.getColumn = function(index) {
return index % this.columns;
this.toString = function() {
return "x: " + this.x + ", y: " + this.y + ", w: " + this.w + ", h:" + this.h + ", columns: " + this.columns + ", rows: " + this.rows + ", cellwidth: " + this.cellWidth() + ", cellheight: " + this.cellHeight();
function Generation(options) {
this.wolfram = options.wolfram;
this.parent = options.parent;
this.state = function(wolfram, parent, i) {
if (i > wolfram.columns - 1) {
if (parent.states.charAt(i) == '0') {
if (parent.states.charAt(i) == '0') {
if (parent.states.charAt(i) == '1') {
var lookup = "" + pre + "" + cur + "" + nex;
return wolfram.getRuleset()[lookup];
this.random = function(wolfram) {
if (Math.random() * 100 < wolfram.baseProp) {
this.states = function(wolfram, parent, randFct, stateFct) {
for (var i = 0; i < wolfram.columns; i++) {
if (parent == undefined) {
s += stateFct(wolfram, parent, i);
}(this.wolfram, this.parent, this.random, this.state);
this.toString = function() {
for (var i = 0; i < this.states.length; i++) {
if (this.states.charAt(i) == '1') {
function Wolfram(columns, rows) {
this.intervals = new IntervalSet(0, 100, parseInt(1 + Math.random() * 6));
this.baseProp = 25 + Math.random() * 50;
this.rulesets = function(prop, num) {
if (Math.random() * 100 < prop) {
var getRuleset = function() {
for (var i = 0; i < num; i++) {
}(25 + Math.random() * 50, this.intervals.num);
this.getRuleset = function() {
return this.rulesets[this.intervals.random()];
this.base = new Generation({
this.generations = function(wolfram, base, num) {
gens.push(new Generation({
for (var i = 1; i < num; i++) {
gens.push(new Generation({
}(this, this.base, this.rows);
this.state = function(column, row) {
if (this.generations[row].states.charAt(column) == '0') {
this.toString = function() {
for (var i = 0; i < this.rows; i++) {
s += this.generations[i] + "\n";
function IntervalSet(min, max, num) {
this.setup = function(container, min, max, num) {
container.push(new Interval(min, max));
var ff = randFloats(min, max, num - 1);
container.push(new Interval(min, ff[0]));
for (var v = 0; v < ff.length - 1; v++) {
container.push(new Interval(ff[v], ff[v + 1]));
container.push(new Interval(ff[ff.length - 1], max));
}(this.ranges, this.min, this.max, this.num);
this.random = function() {
if (this.ranges.length == 1) {
var r = this.min + Math.random() * (this.max - this.min);
for (var i = 0; i < this.ranges.length - 1; i++) {
if (this.ranges[i].contains(r)) {
return this.ranges.length - 1;
this.toString = function() {
var s = this.num + ": " + "{ ";
for (var i = 0; i < this.ranges.length - 1; i++) {
s += this.ranges[i] + ", ";
s += this.ranges[this.ranges.length - 1] + " }";
function Interval(min, max) {
this.contains = function(val) {
return val >= this.min && val < this.max;
this.toString = function() {
return "[" + this.min + ", " + this.max + "]";
function randFloats(min, max, num) {
var create = function(min, max, num, next) {
for (var i = 0; i < num; i++) {
ff.push(min + Math.random() * (max - min));
var sort = function(ff) {
for (let i = 0; i < ff.length - 1; i++) {
return create(min, max, num, sort);