shiffman_pearson_textbook · geneticAlgorithmString
Genetic Algorithm (Evolve Toward Target String)
A textbook genetic algorithm that evolves a population of binary strings toward a target ASCII string (default 'HELLO WORLD!'). Each character is 8 bits MSB-first, so the gene length is 8 * len(target). Per generation: (1) evaluate fitness = Hamming match count, (2) tournament selection with tournament_size contestants, (3) single-point crossover with prob crossover_rate, (4) per-bit mutation with prob mutation_rate, (5) replace population; elitism preserves the top-N. The canvas shows the current population as a binary matrix (each row = individual, match/miss colour per bit), the best individual decoded above the grid, and a fitness curve (mean + best) at the bottom across the last history_max generations.
Original: https://natureofcode.com/evolutionary-computing/
▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.
Math essence
Per generation: fit = (pop == target).sum(axis=1); tournament = argmax(fit[randint(0, pop, tournament_size)]); crossover = single-point cut at randint(1, gene_len) with prob crossover_rate; mutate = bit-flip with prob mutation_rate. Elitism carries top-N over. Vectorised over numpy arrays; ASCII encode/decode uses (bit * 2^(7-i)).sum() per byte. Canvas: per-cell rectangle based on pop[r, c] vs target_bits[c]; curve at bottom uses Bresenham-style line stroke.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 480 | 200–1200 | |
target | str | HELLO WORLD! | — | ASCII target string; each char is 8 bits. |
pop_size | int | 80 | 10–400 | |
tournament_size | int | 5 | 2–20 | |
crossover_rate | float | 0.7 | 0–1 | |
mutation_rate | float | 0.01 | 0–0.2 | |
elitism | int | 2 | 0–20 | |
history_max | int | 80 | 10–400 | |
bg_color | tuple | 15,16,24 | — | |
match_color | tuple | 220,230,255 | — | |
miss_color | tuple | 40,36,50 | — | |
curve_color | tuple | 255,200,90 | — | |
best_color | tuple | 130,255,170 | — | |
seed | int | null | 0–999999 |
Reference
First 60 lines of reference.py. Full source:
library_external/shiffman_pearson_textbook/geneticAlgorithmString/reference.py
from __future__ import annotations
from typing import ClassVar
import numpy as np
class GeneticAlgorithmString:
"""Genetic algorithm evolving toward a target string.
A population of ``pop_size`` binary strings of length
``gene_len = 8 * len(target)`` (each ASCII char is 8 bits, MSB first)
evolves under a textbook GA loop (Holland 1975; Mitchell 1996) at
each ``step(n)`` call:
1. **Evaluate**: each individual's fitness is the count of bits
matching the target (Hamming similarity).
2. **Select**: ``tournament_size``-way tournament with replacement
picks a parent.
3. **Crossover**: single-point crossover with probability
``crossover_rate``.
4. **Mutate**: each bit is flipped with probability ``mutation_rate``.
5. The new population replaces the old (generational GA, elitism
optional).
``step(n)`` runs ``n`` generations. The canvas shows the current
population as a binary matrix (each row is an individual; white =
matching bit, dark = mismatching bit) at the top, with a fitness
curve (mean and best across generations) at the bottom and the
current best individual decoded as ASCII above.
Pearson (*Generative Art* Ch. 5 'Evolution') and Shiffman
(*Nature of Code* Ch. 9 'Evolutionary Computing') both feature this
exact example as the simplest nontrivial GA.
"""
family: ClassVar[str] = "shiffman_pearson_textbook"
sketch: ClassVar[str] = "geneticAlgorithmString"
def __init__(
self,
dim: int = 480,
target: str = "HELLO WORLD!",
pop_size: int = 80,
tournament_size: int = 5,
crossover_rate: float = 0.7,
mutation_rate: float = 0.01,
elitism: int = 2,
history_max: int = 80,
bg_color: tuple[int, int, int] = (15, 16, 24),
match_color: tuple[int, int, int] = (220, 230, 255),
miss_color: tuple[int, int, int] = (40, 36, 50),
curve_color: tuple[int, int, int] = (255, 200, 90),
best_color: tuple[int, int, int] = (130, 255, 170),
seed: int | None = None,
) -> None:
self.dim = dim
self.bg_color = np.array(bg_color, dtype=np.float32)
self.match_color = np.array(match_color, dtype=np.float32)
self.miss_color = np.array(miss_color, dtype=np.float32) Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/shiffman_pearson_textbook/geneticAlgorithmString/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from shiffman · pearson
Lindenmayer L-System (Textbook Formulation)
shiffman_pearson_textbook · lindenmayerTextbook
Lindenmayer L-system string rewriting with a 2-D turtle interpreter, the canonical textbook formulation used in both Shiffman's Nature of Code Ch.
Mandelbrot Set (Escape-Time Fractal)
shiffman_pearson_textbook · mandelbrotSet
The Mandelbrot set rendered by escape-time iteration of z = z^2 + c on a window of the complex plane.
Perlin Noise Flow Field
shiffman_pearson_textbook · perlinFlowField
A 2-D scalar field of Perlin gradient noise is sampled on a coarse grid; each cell is assigned a heading theta = 2*pi * n.
Random Walk / Drunkard's Walk
shiffman_pearson_textbook · randomWalkDrunkard
Many random walkers each start at the canvas center and take a stochastic 2-D step every tick.
Reynolds Boids (Separation / Alignment / Cohesion)
shiffman_pearson_textbook · boidsClassic
Reynolds' classic boids flocking model.
Stochastic Recursive Fractal Tree
shiffman_pearson_textbook · recursiveTree
Stack-based stochastic fractal tree from Shiffman's Nature of Code Ch.