Genetic algorithms, fitness functions, selection, crossover, and mutation — letting evolution discover solutions we never could design by hand.
So far, we have been the intelligent designers. We chose the variables, the forces, the rules. But what if we could let a process found in nature — evolution — decide for us?
The infinite monkey theorem: a monkey hitting keys randomly on a typewriter will eventually type Shakespeare. But the probability of typing even "to be or not to be" is (1/27)39 — a number so astronomically small that the monkey would need to type for longer than the age of the universe.
We'll start by evolving a phrase (a problem with a known answer, to test our algorithm), then discuss how to apply the same technique to any problem.
Three principles must be present for natural selection to work:
| Principle | What it means | In our code |
|---|---|---|
| Heredity | Children inherit properties from parents | DNA is copied from parent to child |
| Variation | Diversity must exist in the population | Random initial DNA + mutation |
| Selection | Some organisms are more fit and more likely to reproduce | Fitness function + mating pool |
Step 1: Create a population of N elements, each with randomly generated DNA.
Each member has a genotype (the raw data — an array of characters) and a phenotype (how that data is expressed — the string displayed on screen).
pseudocode class DNA: genes = new array[targetLength] for i in genes.length: genes[i] = randomChar(32, 128) # ASCII printable # Create population population = new DNA[200]
Step 2a: Evaluate each member's fitness. This is a numeric score that says "how good is this solution?"
For our typing monkey: fitness = correct characters / total characters
pseudocode function calcFitness(): score = 0 for i in genes.length: if genes[i] == target[i]: score += 1 fitness = score / target.length
fitness = (correct/total)2 or even 2correct. This rewards perfection exponentially and speeds convergence.Step 2b: Build a mating pool. High-fitness members get more "tickets" in the pool. Selection is probabilistic — the wheel of fortune method.
pseudocode matingPool = [] for member in population: n = member.fitness * 100 for j in n: matingPool.add(member)
Now if you pick two random members from the mating pool, the probability of selecting any given member is proportional to its fitness.
Step 3a: Pick two parents from the mating pool. Combine their DNA to create a child.
The random midpoint method: pick a random index. Everything before it comes from parent A; everything after comes from parent B.
pseudocode function crossover(partnerA, partnerB): child = new DNA() midpoint = random(0, genes.length) for i in genes.length: if i < midpoint: child.genes[i] = partnerA.genes[i] else: child.genes[i] = partnerB.genes[i] return child
Step 3b: After crossover, each gene has a small probability of being replaced with a random value. This is mutation.
pseudocode mutationRate = 0.01 # 1% for i in genes.length: if random(1) < mutationRate: genes[i] = randomChar(32, 128)
| Mutation Rate | Effect |
|---|---|
| 0% | May never solve; depends on initial luck |
| 1% | Sweet spot — new variation without destroying progress |
| 5% | Works but slower convergence |
| 10%+ | Effectively random — evolution breaks down |
The full genetic algorithm loop:
Watch a genetic algorithm evolve a target phrase in real time. Each generation, the best phrases reproduce and the population converges on the answer.
The algorithm starts with random phrases and evolves toward the target using selection, crossover, and mutation.
| Topic | Key Takeaway |
|---|---|
| Genetic algorithms | Evolutionary search: population → fitness → selection → reproduction → repeat |
| Three principles | Heredity, variation, selection |
| Fitness function | The numeric score you must design for each problem |
| Selection | Probabilistic (wheel of fortune), not elitist |
| Crossover | Random midpoint or coin flip to combine parent DNA |
| Mutation | Small random changes to maintain diversity (~1%) |
| Genotype/Phenotype | DNA is data; the creature/image/behavior is expression |
What we covered:
• Darwinian natural selection
• Population, fitness, mating pool
• Crossover and mutation
• Population size and mutation rate
• Genotype vs. phenotype
What comes next:
Chapter 10: Neural Networks. The perceptron, weighted inputs, supervised learning, and the beginnings of artificial intelligence. Our objects will learn from experience.