I’ve been working lately with the Heliconius research group at the University of Cambridge on a game to explain the evolution of mimicry in butterfly wing patterns. It’s for use at the Summer Science Exhibition at the Royal Society in London, where it’ll be run on a large touch screen for school children and visiting academics to play.
The game models biological processes for education purposes (as opposed to the genetic programming as used on the camouflage egg game), and the process of testing this, and deciding what simplifications are required has become a fascinating part of the design process.
In biosciences, genetics are modelled as frequencies of specific alleles in a given population. An allele is a choice (a bit like a switch) encoded by a gene, so a population can be represented as a list of genes where each gene is a list of frequencies of each allele. In this case the genetics consists of choices of wing patterns. The game is designed to demonstrate the evolution of an edible species mimicking a toxic one – we’ll be publishing the game after the event. A disclaimer, my terminology is probably misaligned in the following code, still working on that.
;; an allele is just a string id and a probability value (define (allele id probability) (list id probability)) ;; a gene is simply a list of alleles ;; return the id of an allele chosen based on probability (define (gene-express gene) (let ((v (rndf))) (car (cadr (foldl (lambda (allele r) (let ((segment (+ (car r) (allele-probability allele)))) (if (and (not (cadr r)) (< v segment)) (list segment allele) (list segment (cadr r))))) (list 0 #f) gene))))) ;; a chromosome is simple list of genes ;; returns a list of allele ids from the chromosome based on probability (define (chromosome-express chromo) (map gene-express chromo))
When an individual is removed from the population, we need to adjust the probabilities by subtracting based on the genetics of the eaten individual, and the adding to the other alleles to keep the probabilities summing to one:
;; prevents the probability from 'fixing' at 0% or 100% ;; min(p,(1-p))*0.1 (define (calc-decrease p) (* (min p (- 1 p)) allele-decrease)) ;; remove this genome from the population (define (gene-remove-expression gene genome) (let ((dec (calc-decrease (allele-probability (car gene))))) (let ((inc (allele-increase dec (length gene)))) (map (lambda (allele) (if (eq? (allele-id allele) genome) (allele-modify-probability allele (- (allele-probability allele) dec)) (allele-modify-probability allele (+ (allele-probability allele) inc)))) gene))))