The Sierpinski triangle drawn via the chaos game — an iterated function system where a point repeatedly jumps halfway toward a randomly chosen triangle vertex, gradually filling in a fractal. Each vertex colours its offspring differently, revealing the three self-similar sub-triangles.
Rendered as coloured blocks via SDL2.
- Sierpinski triangle via the chaos game iterated function system
- 200 points per frame at ~40 fps
- Per-vertex colour coding: coral, cyan, gold
- True 24‑bit color rendering via SDL2 framebuffer
- 960 × 480 window (80 × 40 grid, 12 px per cell)
- Live point counter in window title
- Accumulating canvas — grid persists across frames
- Keyboard and Ctrl-C quit handling
- Written entirely in C
Three fixed vertices define a triangle. A moving point starts at the centre, then repeatedly picks a random vertex and moves halfway toward it, marking each position on the grid. After a few thousand iterations the Sierpinski fractal emerges from the seemingly random motion. Each vertex's branch is drawn in a distinct colour, revealing the three-way self-similarity.
The fractal is drawn onto an 80 × 40 grid of unsigned bytes. 0 means empty; 1, 2, or 3 records which vertex last claimed that cell:
#define W 80
#define H 40
unsigned char grid[H][W];
memset(grid, 0, sizeof(grid));Each frame, the grid is rendered as coloured 12 × 12 pixel blocks in an SDL2 surface.
Three corners span the triangle in screen coordinates:
int vx[3] = {0, W - 1, W / 2};
int vy[3] = {H - 1, H - 1, 0};| Vertex | Position | Colour |
|---|---|---|
| 0 | Bottom-left | Coral (255, 80, 80) |
| 1 | Bottom-right | Cyan (80, 220, 255) |
| 2 | Top-centre | Gold (255, 220, 80) |
The core algorithm is an iterated function system (IFS):
double px = W / 2.0, py = H / 2.0; /* starting point */
for (int k = 0; k < 200; k++) {
int i = rand() % 3; /* pick a random vertex */
px = (px + vx[i]) / 2.0; /* jump halfway */
py = (py + vy[i]) / 2.0;
int ix = (int)px, iy = (int)py;
if (ix >= 0 && ix < W && iy >= 0 && iy < H)
grid[iy][ix] = 1 + i; /* mark with vertex colour */
}The key insight: repeatedly jumping halfway toward a randomly chosen vertex always converges to the Sierpinski triangle, regardless of the starting position. The first few hundred points may fall outside the fractal, but they are quickly buried by correct ones.
Each cell stores 1 + vertex_index (1, 2, or 3) so the renderer can colour it by origin vertex:
Uint32 col_v[3] = {
SDL_MapRGB(fmt, 255, 80, 80), /* coral */
SDL_MapRGB(fmt, 80, 220, 255), /* cyan */
SDL_MapRGB(fmt, 255, 220, 80), /* gold */
};
for (each cell) {
Uint32 color = grid[y][x] ? col_v[grid[y][x] - 1] : col_bg;
/* fill CELL × CELL block */
}The three colours make the three-way recursive subdivision immediately visible: each vertex's "territory" forms a distinct third of the fractal.
Each cell is drawn as a 12 × 12 pixel block:
for (int py = 0; py < CELL; py++)
for (int px = 0; px < CELL; px++)
pixels[(y * CELL + py) * pitch + (x * CELL + px)] = color;Empty cells render as a near-black navy background.
200 points are computed per frame. The grid persists across frames — once a cell is marked it stays marked:
for (int k = 0; k < 200 && running; k++) {
/* ... jump and mark ... */
}The window title updates each frame with the cumulative count:
snprintf(title, sizeof title, "Chaos Game — %ld points", step);
SDL_SetWindowTitle(win, title);A 40 fps cap keeps CPU usage low:
Uint32 elapsed = SDL_GetTicks() - frame_start;
if (elapsed < 25) SDL_Delay(25 - elapsed);git clone <this-repo>
cd chaos
make
Or manually:
gcc chaos.c -o chaos $(sdl2-config --cflags --libs)
Dependencies: SDL2 and a C compiler (gcc/clang).
Install SDL2 via Homebrew:
brew install sdl2
Or apt:
sudo apt install libsdl2-dev
./chaos
Controls:
- ESC or Q — quit
- Ctrl-C — quit (fallback)
Edit constants at the top of chaos.c:
W,H— grid resolutionCELL— pixel size per cell- Vertex positions
vx,vy— change the triangle shape - Vertex colours
col_v[]— any RGB triple - Batch size (
200) — points per frame
- Iterated function systems (IFS) for fractal generation
- Chaos game algorithm (random midpoint displacement)
- Sierpinski triangle — three-way recursive self-similarity
- Per-vertex colour coding to reveal sub-structure
- Accumulating grid buffer (write-once, render-each-frame)
- SDL2 surface/pixel-buffer graphics
- Cell-based block rendering
- Real-time animation with frame-rate capping
SDL.h— window management and pixel bufferstdio.h—snprintf, stderr diagnosticsstdlib.h—rand,srand,NULLstring.h—memsettime.h—timefor RNG seedsignal.h—SIGINThandler