#!perl

use strict;
use warnings;

=head1 NAME

  4thga.pl - Fourth iteration of an evolutionary algorithm in Perl

=head1 SYNOPSIS

  prompt$ perl 4thga.pl <reproductive pool proportion>

=head1 DESCRIPTION

This is an evolutionary algorithm that uses mutation to make a set of strings  evolve so that they approximate "yetanother". The strings are lowercase letters, plus _, which is conventionally situated at the end of the alphabet. 

Each generation, a string is picked up, mutated, and, if the result is better than the original one, replaces the worst one.

Overall, distance to the aforementioned string should be minimized

=cut 

require "LittleEA.pm";

#Declare variables
my $poolProportion = shift || 0.5; 
my $newGenProportion = shift || 0.5 ; #Percentage of population substituted each generation
my $popSize = 100; # No need to keep it variable
my $targetString = 'yetanother';
my $strLength = length( $targetString );
my @alphabet = ('a'..'z');

#Declare some subs (not the best place to do it, but we are going to
#need them
sub fitness ($;$) {
  my $string = shift;
  my $distance = 0;
  for ( 0..($strLength -1)) {
    $distance += abs( ord( substr( $string, $_, 1)) -   ord( substr( $targetString, $_, 1)));
  }
  return $distance;
}


#Create and print initial population
my @population = initPopulation( $popSize, $strLength, \@alphabet );
printPopulation( \@population);

#Sort population
@population = sort { $a->{_fitness} <=> $b->{_fitness} } @population;

#Go ahead with the algorithm
do {
  for ( my $i = 0; $i < $popSize*$newGenProportion; $i ++ ) {
    my $chr1 = $population[ rand( $#population*$poolProportion)];
    my $chr2 = $population[ rand( $#population*$poolProportion)];
    my $clone1 ={};
    my $clone2 ={};
    $clone1 = { _str => $chr1->{_str},
		_fitness => 0 };
    $clone2 = { _str => $chr2->{_str},
		_fitness => 0 };
    mutate( $clone1, \@alphabet );
    mutate( $clone2, \@alphabet );
    crossover( $clone1, $clone2 );
    $clone1->{_fitness} = fitness( $clone1->{_str} );
    $clone2->{_fitness} = fitness( $clone2->{_str} );
    $population[$#population]=$clone1;
    $population[$#population-1]=$clone2;
    
    #Re-sort
    @population = sort { $a->{_fitness} <=> $b->{_fitness} } @population;
  }

  #Print best
  print "Best so far: $population[0]->{_str} =>  $population[0]->{_fitness}\n";

  #Early exit
} until $population[0]->{_fitness} == 0;
printPopulation();



  
