Hello everyone. Some months ago I made a Processing sketch to experiment with the game of chaos. I coded different versions of it and managed to create lots of interesting images with them. In this post I am going to publish some of the versions along with images created with each.
What is the game of chaos?
The chaos game is essentially letting a point inside a convex polygon move under certain rules. In its most basic form, the game goes as follows.
In each iteration, chose a polygon's vertex at random and move towards it. The distance to travel is always a fixed fraction of the distance between the picked vertex and the point.
By trying different polygons, different 'fixed fractions', playing with colours and adding restrictions to how to choose the vertices; you can create very interesting pictures. As a teaser, if you look at my profile picture, it was made this way.
First version (bare basics).
Here I share the most basic version of my code, in case someone wants to build something from it. Nothing very interesting can be drawn with it beyond the Sierpinsky's triangle though.
Main sketch class
/*
The chaos game.
A bare basic implementation of the chaos game.
The game of chaos boils down to drawing a sequence of points
inside a CONVEX polygon that are generated following certain rules.
The rules are the following.
Given a convex polygon, a point P inside it and a number r
between 0 and 1; these steps are carried out:
1. Choose at random one of the polygon's vertices (v).
2. Generate the next point P' by this formula P' = P + r * (v - P).
3. Draw P'.
4. Repeat the previous steps with P'.
Under suitable choices for r and the polygon, the sequence of points
depicts a fractal set.
For more information on the chaos game and take ideas for tinkering,
you can have a look at https://en.wikipedia.org/wiki/Chaos_game
*--------------------*
* Keyboard controls: *
*--------------------*
- 'p' to pause the execution.
- 'r' to resume the execution.
- 's' when execution is paused, saves the canvas to a png image
whose name's held by the variable 'img_name'.
*/
Point p; // point to iterate inside the polygon
float adv_ratio; // advance ratio
int max_iter; // number of iterations to quit the sketch at
boolean is_exec_paused; // state of the sketch
String img_name = "prova.png"; // name of the image to save the canvas to
void setup() {
fullScreen();
frameRate(60);
background(0);
stroke(255); // colour of the point
strokeWeight(1.5);
strokeCap(PROJECT);
max_iter = int(frameRate) * 60 * 10; // 10 minutes
is_exec_paused = false;
/*adv_ratio = .5f in a triangle yields Sierpinski's triangle*/
adv_ratio = .5f;
initial_setting();
}
void draw() {
p.iterate();
if (frameCount > frameRate * 20) { // dismiss some initial points (20 sec)
p.draw();
}
// when reached the maximum of iterations, save the canvas and quit
if (frameCount == max_iter) {
println("Maximum number of iterations reached: " + max_iter);
save_and_quit();
}
}
/**
Create convex polygon and initialize the point.
This function holds all the code for creating the polygon
and the point. It prevents the setup() function from becoming a mess.
Comment or uncomment the lines of the polygon you want to use;
or add your own.
*/
void initial_setting() {
PVector[] polygon; // convex polygon's vertices
/*triangle*/
polygon = new PVector[3];
polygon[0] = new PVector(width / 2, 0);
polygon[1] = new PVector(0, height);
polygon[2] = new PVector(width, height);
// initialize the point, make sure it lies inside the polygon!
p = new Point(0, 0, adv_ratio);
p.x = width / 2 + random(- 50, 50);
p.y = random(height / 2, height);
p.polygon = polygon;
/*--end triangle--*/
/*rectangle (whole screen)*/
//polygon = new PVector[4];
//polygon[0] = new PVector(0, 0);
//polygon[1] = new PVector(width, 0);
//polygon[2] = new PVector(width, height);
//polygon[3] = new PVector(0, height);
//// initialize the point, make sure it lies inside the polygon!
//p = new Point(0, 0, adv_ratio);
//p.x = random(width);
//p.y = random(height);
//p.polygon = polygon;
/*--end rectangle--*/
/*regular polygon*/
//int q_edges = 5; // what regular polygon to create
//float cx = width / 2, cy = height / 2; // polygon's center
//float radius = 3 * width / 5; // change this to resize the polygon
//float step_angle = 2 * PI / q_edges;
//float ini_angle = PI / 2; // initial vertex on top
//polygon = new PVector[q_edges];
//for (int i = 0; i < polygon.length; i++) {
// polygon[i] = new PVector(
// cx + radius * cos(i * step_angle + ini_angle),
// cy - radius * sin(i * step_angle + ini_angle));
//}
//// initialize the point, make sure it lies inside the polygon!
//p = new Point(0, 0, adv_ratio);
//p.x = width / 2 + random(- 50, 50);
//p.y = height / 2 + random(-50, 50);
//p.polygon = polygon;
/*--end regular polygon--*/
}
/**Save the canvas to a file.
The name of the file is held by the variable 'img_name'.
*/
void save_and_quit() {
println("Saving the canvas to \"" + img_name + "\"");
save(img_name);
noLoop();
exit();
}
/**Keyboard controls for the sketch.
- 'p' to pause the execution.
- 'r' to resume the execution.
- 's' when execution is paused, saves the canvas to a png image
whose name's held by the variable 'img_name'.
*/
void keyPressed() {
if (is_exec_paused) {
if (key == 'r' || key == 'R') {
is_exec_paused = false;
println("Execution resumed");
loop();
} else if (key == 's' || key == 'S') {
println("Saving the canvas to \"" + img_name + "\"");
save(img_name);
}
} else {
if (key == 'p' || key == 'P') {
is_exec_paused = true;
println("Execution paused");
noLoop();
}
}
}
Point class
/**
Class representing a point as in the chaos game.
In the game of chaos a point moves inside a convex polygon
by moving towards a randomly selected vertex in each iteration.
The distance the point travels to the vertex is a fixed fraction
of the distance they are apart.
We will call that fixed fraction 'advance ratio'.
In each iteration, the new position of the point
is computed as follows:
P' = P + r * (v - P)
Where:
-P' are the new point's coordinates.
-P are the current point coordinates.
-r is 'advance ratio', 0 < r < 1.
-v are the coordinates of the randomly chosen vertex.
The game is played by repeatedly calling 'iterate()' and 'draw()'.
*/
class Point {
float x, y; // coordinates of the point
float r; // advance ratio
PVector[] polygon; // polygon's vertices
Point(float x, float y, float adv_ratio) {
this.x = x;
this.y = y;
r = adv_ratio;
}
/**Generates the new coordinates of the point.*/
void iterate() {
int i;
// choose a vertex at random
i = int(random(polygon.length));
// compute the next coordinates
x += (polygon[i].x - x) * r;
y += (polygon[i].y - y) * r;
}
void draw() {
point(x, y);
}
}
With this you can create the Sierpinsky's triangle
Tweak ideas
Instead of drawing the point like this
class Point{
...
void draw() {
point(x, y);
}
}
we can try drawing small rectangles with some suitable transparency value, so the image looks slightly smoother.
class Point{
...
/**Assume rectMode(CENTER) is enabled.*/
void draw() {
fill(255, 100);
rect(x, y, 4, 4);
}
}
Also we could spice things up with colours and get images like this
Which was obtained by assigning a colour to each vertex of the triangle and drawing the point with the colour of the vertex that was picked up in each iteration.