package MyCritters; my $size; BEGIN { $size = shift || 10; } ## set up a default critter class using an array representation: use ArrayEvolver alphabet => [0 .. $size-1], mutation_rate => 1/$size, gene_length => $size; @ISA = ('ArrayEvolver'); ## add a new method: sub as_sentence { my $critter = shift; sprintf "This sentence contains " . join(", " => map qq[%d "$_"s], 0 .. $size-1), @{ $critter->gene }; } ## override the default fitness method: sub fitness { my $critter = shift; my $sentence = $critter->as_sentence; my $differences; for (0 .. $size-1) { my $count = () = $sentence =~ /($_)/g; $differences += abs( $count - $critter->gene->[$_] ); } return $size*$size - $differences; } ############# package main; use Algorithm::Evolve; ## this gets called after every generation: sub callback { my $p = shift; printf "score = %d/%d after %d generations\n", $p->best_fit->fitness, $size*$size, $p->generations unless $p->generations % 100; $p->suspend if $p->generations >= 1000 or $p->best_fit->fitness == ($size*$size); } ## set up a population object: my $p = Algorithm::Evolve->new( critter_class => 'MyCritters', selection => 'roulette', replacement => 'random', parents_per_gen => 10, size => 100, random_seed => shift, callback => \&callback ); $p->start; printf "%s (score = %d/%d)\n", $p->best_fit->as_sentence, $p->best_fit->fitness, $size*$size;