A mathematical topic that has always fascinated me is Chaos Theory. At a foundational level, Chaos Theory states that even the most random of systems have underlying laws and patterns that can create ordered outcomes. In other words, order can be born out of chaos.
A fun game that gives a sneak peek into Chaos Theory is what is often known as the Chaos Game. In this article, I will be explaining how the Chaos Game is played and showing you how you can simulate it fairly easily in Javascript with p5.js and Codesphere.
To get a sneak peek of the project, you can run it in Codesphere, an online development, and deployment tool, here:
https://codesphere.com/ide/menu/apps/new
Keep in mind that you will have to make a free account if you have not used Codesphere before. Once the Codesphere environment is created, you can deploy the app by running:
npm ci && node server.js
You can find more information on Codesphere here:
The Chaos Game
The chaos game begins by drawing three corners of a triangle, and a point in the center of the triangle. We’ll label our corners A, B, and C.
Now pick one of our corners at random. Say we choose A, draw an additional point halfway between the center and A.
Now repeat the process again, picking a random corner(C in this case), and drawing a point halfway between C and our most recent point.
The Chaos Game is interested in what occurs if you repeat this process continually. Will the entire triangle be filled up? Will the points be concentrated around the edges? Since we are picking the corners at random, maybe there will be no pattern at all?
Well, it turns out that a pattern does emerge: The Sierpinski Triangle.
Even more interesting than this fractal, is the fact that the Sierpinski Triangle occurs in other places in Mathematics, such as Pascal’s Triangle(When you fill in all odd numbers):
Setting up our Environment
Let’s get started! If you are using Codesphere create an empty project. If you are not, create an empty directory.
Next, initialize npm:
npm init
We are going to create two files: server.js to run our express server, and a index.html file for our webpage.
touch server.js index.html
Finally, install ExpressJS, a NodeJS framework for creating web servers:
npm i express
Serving our HTML Page
For this project we are going to use Express to serve our html page that will contain our relevant code. To do this, we write the following code in our server.js file:
var express = require('express'); // Require the Express NPM package | |
var app = express(); // Initialize our app | |
var path = require('path'); // Library neccesary for locating the path of our HTML | |
app.get('/', function(req, res) { // When someone enters our site | |
res.sendFile(path.join(__dirname + '/index.html')); //Serve them the index.html file | |
}); | |
app.listen(3000); //Run this server on port 3000 |
To run our server on port 3000, we can just run:
node server.js
However, we haven’t yet put anything in our index.html
file, so we’ll just get a blank screen.
Graphing Our Triangle
The next step is to start displaying our necessary graphics. In order to plot points, we’ll be using p5.JS, an easy-to-use javascript graphical library.
https://p5js.org/
We can access p5js with the following extremely long CDN:
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js" integrity="sha512-WIklPM6qPCIp6d3fSSr90j+1unQHUOoWDS4sdTiR8gxUTnyZ8S2Mr8e10sKKJ/bhJgpAa/qG068RDkg6fIlNFA==" crossorigin="anonymous"></script>
Note, that we will also be creating a text field for the user to enter the number of iterations that they want to play the game for, which we can also use p5.js to make.
<head> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js" integrity="sha512-WIklPM6qPCIp6d3fSSr90j+1unQHUOoWDS4sdTiR8gxUTnyZ8S2Mr8e10sKKJ/bhJgpAa/qG068RDkg6fIlNFA==" crossorigin="anonymous"></script> | |
<script> | |
const screenDim = 600 // Our dimensions for the canvas | |
let corners = [{x: 300, y: 100}, {x: 100, y: 450}, {x: 500, y: 450}] // The three corners of our triangle | |
let pts = [{x: corners[0].x, y: (corners[0].y + corners[1].y) / 2}] // An array for all the points we iterate through, initialize with our starting point | |
let num = 10 // Number of iterations | |
let numField, numLbl // Declare our label and textfield to change the numbers | |
function setup() { | |
createCanvas(screenDim,screenDim); // Create our canvas for p5 to draw on | |
//Create our number TextField to the right of our canvas, with our inpEvent() function as the input event: | |
numField = createInput(num) | |
numField.position(screenDim + 100, 100) | |
numField.size(50) | |
numField.input(inpEvent) | |
//Create the number label on the left size of our numField | |
numLbl = createP("# of Points:") | |
numLbl.position(screenDim + 15, 85) | |
drawScreen() // Draw the screen when the app first starts up | |
} | |
function inpEvent() { //This function responds to changes in the number of points | |
pts = [{x: corners[0].x, y: (corners[0].y + corners[1].y) / 2}] //Reset the pts array | |
num = this.value() //Change the number value | |
let randInd | |
for(let i = 1; i < num; i++) { // Add a point for each iteration | |
randInd = floor(random(0, 3)) // Pick a random corner | |
pts.push({ | |
x: (pts[i - 1].x + corners[randInd].x) / 2, | |
y: (pts[i - 1].y + corners[randInd].y) / 2 | |
}) // Push a new point to the array between the last point and the random corner | |
} | |
drawScreen() // Draw screen once all our points our calculated | |
} | |
function drawScreen() { // Function to draw the points | |
clear() // Clear all previous points | |
fill(250); // Set the fill color to white | |
square(0,0, screenDim) // Draw a square around our canvas | |
fill("black") // Set the fill color to black | |
corners.forEach((pt) => { //Draw each of the corners of our triangle | |
ellipse(pt.x, pt.y, 10) //Ellipse with radius 10 | |
}) | |
fill("blue") // Set the fill color to blue | |
pts.forEach((pt, index) => { // Iterate through our points | |
setTimeout(() => { // Add a nice delay for animation effect | |
ellipse(pt.x, pt.y, 5) // Draw the point with radius 5 | |
}, (5000 / num) * index) // We want the animation to take 5 seconds no matter what, so increment the delays by 5000/num | |
}) | |
} | |
</script> | |
</head> |
If we deploy our code, we should see the following:
And there you have it! In only around 50 lines of code we can simulate the Chaos Game and generate an amazing fractal!
Next Steps
Now if you are looking to play around with the Chaos Game some more, I’d encourage some of the following variations:
- What happens if you change the starting point? What if you start at one of the corners? What if you start outside the triangle?
- What happens if you change the corners of the triangle? What if it is a right triangle?
- Can this game be played in 3D with a pyramid?
Top comments (1)
Wow! This looks interesting.