use strict; use warnings; use constant CHROMOSOMES => 30; use constant TARGET => scalar <>; use constant TARGET_BITS => 8 * length TARGET; use constant P_MUTATION => 0.5; use constant OK_ENOUGH => 1; # Too much is just enough sub say { my $say = join '', @_; $say =~ s/([^[:print:]])/sprintf '\x%02x', ord $1/ge; print "$say\n"; } # Birth. my @population = map { random_chromosome() } 1 .. CHROMOSOMES; my $result; while ( not defined $result ) { # Test the fitness of every chromosome. my @fitness; CHROMOSOME: for my $chromosome ( @population ) { my $fitness = fitness( $chromosome ); if ( $fitness >= OK_ENOUGH ) { $result = $chromosome; last CHROMOSOME; } push @fitness, $fitness; } my @order = sort { $fitness[$b] <=> $fitness[$a] } 0 .. $#fitness; say "$fitness[$order[0]]: $population[$order[0]]"; # Trial by foxes. splice @order, @order / 3; @population = @population[ @order ]; # Sex. my @children = map { sex( @population ) } 1 .. CHROMOSOMES - @population; push @population, @children; } say $result; sub sex { my @parents = @_; my $child = ''; for ( 0 .. TARGET_BITS - 1 ) { vec( $child, $_, 1 ) = vec( $parents[ rand @parents ], $_, 1 ); } if ( P_MUTATION < rand ) { my $bit = int rand TARGET_BITS; vec( $child, $bit, 1 ) = not vec( $child, $bit, 1 ); } return $child; } sub fitness { my $chromosome = shift @_; my $matches = 0; for ( 0 .. TARGET_BITS - 1 ) { $matches++ if vec( TARGET, $_, 1 ) == vec( $chromosome, $_, 1 ); } my $fitness = $matches / TARGET_BITS; return $fitness; } sub random_chromosome { my $chromosome = ''; for ( 0 .. TARGET_BITS - 1 ) { vec( $chromosome, $_, 1 ) = rand 2; } return $chromosome; }