=begin pod Algorithm::DawkinsWeasel is a simple model illustrating the idea of cumulative selection in evolution. The original form of it looked like this: 1. Start with a random string of 28 characters. 2. Make 100 copies of this string, with a 5% chance per character of that character being replaced with a random character. 3. Compare each new string with "METHINKS IT IS LIKE A WEASEL", and give each a score (the number of letters in the string that are correct and in the correct position). 4. If any of the new strings has a perfect score (== 28), halt. 5. Otherwise, take the highest scoring string, and go to step 2 This module parametrizes the target string, mutation threshold, and number of copies per round. The goal is to be able to use it something like this: my $weasel = Algorithm::DawkinsWeasel.new; say $weasel.current-phrase while $weasel; =end pod unit class Algorithm::DawkinsWeasel:ver<0.0.2> does Iterator; has Str @.target-phrase; has Rat $.mutation-threshold; has Int $.copies; has Str @!charset; has Int $!count; has Str @!current-phrase; has Int $!hi-score; submethod BUILD(Str :$target-phrase = 'METHINKS IT IS LIKE A WEASEL', Rat :$mutation-threshold = 0.05, Int :$copies = 100) { @!target-phrase = $target-phrase.comb; $!mutation-threshold = $mutation-threshold; $!copies = $copies; } submethod TWEAK { @!charset = | ['A' .. 'Z'] , ' '; @!current-phrase = map { @!charset.pick }, 0 .. @!target-phrase.end; $!hi-score = 0; $!count = 0; } method evolve { for (1 .. $!copies) { my @trial = map { 1.rand < $!mutation-threshold ?? @!charset.pick !! $_; }, @!current-phrase; my Int $score = 0; for 0 .. @!target-phrase.end -> $i { if @trial[$i] eq @!target-phrase[$i] { $score++; } } if $score > $!hi-score { $!hi-score = $score; @!current-phrase = @trial; } } } method pull-one { $!count++; self.evolve; return $!hi-score == @!target-phrase.elems ?? IterationEnd !! self; }