#!/usr/bin/perl -w #This program will evolve digital organisms in a way specified by the user use strict; use warnings; my($separator) = "*" x 50; print "\n" . $separator . "\n" . "Welcome to Darwin's World!!\nThis is Evolution version1\nAuthor: Mario A. Fares\nDepartment of Genetics, University of Dublin, TCD\n$separator\n\n"; print "--Your mission is to evolve an organism to adapt to an environment created by you\n"; print "To create your environment, set the parameters below and choose your preferred organism\nto start your evolution with\n\n"; my($pop_size, $temperature, $oxygen, $food, $mutation_rate, $number_generations, $bottleneck, $initial_organism); print "Population size: "; $pop_size = ; chomp $pop_size; if(($pop_size <1) || ($pop_size >100000000)) { print "What if you try to use a sensible size!!\n"; exit; } print "\nTemperature of your environment (1 to 9) (1: cold; 9: hot):"; $temperature = ; chomp $temperature; if(($temperature < 1) || ($temperature > 9)) { print "\nYea yea, very funny but you have to follow the rules!!!\nTry again ;)\n\n"; exit; } print "\nOxygen in the air (1 to 9) (1: little oxygen; 9: very oxygenized):"; $oxygen = ; chomp $oxygen; if(($oxygen < 1) || ($oxygen > 9)) { print "\nYea yea, very funny but you have to follow the rules!!!\nTry again ;)\n\n"; exit; } print "\nAmount of available food (1 to 9) (1: very scarse; 9: abundant):"; $food = ; chomp $food; if(($food < 1) || ($food > 9)) { print "\nYea yea, very funny but you have to follow the rules!!!\nTry again ;)\n\n"; exit; } print "\nMutation rate (this is the proportion of individuals in the population that will mutate):"; $mutation_rate = ; chomp $mutation_rate; print"\nNumber of generations of replicative population:"; $number_generations = ; chomp $number_generations; if($number_generations < 2) { print "You don't seem up for multiplying do you :D\nTry again, don't be lazy :D\n\n"; exit; } print "\nBottleneck (example: 0.1 means 90% of the population will pass to next generation):"; $bottleneck = ; chomp $bottleneck; if(($bottleneck < 0) || ($bottleneck > 1)) { print "Bad choice!! Bottleneck should be a number ranging between 0 and 1\nTry again\n\n"; exit; } print "\nInitial organism:"; $initial_organism = ; chomp $initial_organism; if(length($initial_organism) == 2) { my(@a_org); $a_org[0] = substr($initial_organism, 0, 1); $a_org[1] = substr($initial_organism, 1, 1); if(($a_org[0] <= 0) && ($a_org[1] <= 0)) { print "Bad choice!! Organism should be composed of two digits, each ranging between 1 and 9\nTry again\n\n"; exit; } }else { print "Bad choice!! Organism should be composed of two digits, each ranging between 1 and 9\nTry again\n\n"; exit; } my($prediction); print "\nWhat is your predicted organism? "; $prediction = ; chomp $prediction; if(length($prediction) == 2) { my(@a_or); $a_or[0] = substr($prediction, 0, 1); $a_or[1] = substr($prediction, 1, 1); if(($a_or[0] <= 0) && ($a_or[1] <= 0)) { print "Bad choice!! Organism should be composed of two digits, each ranging between 1 and 9\nTry again\n\n"; exit; } }else { print "Bad choice!! Organism should be composed of two digits, each ranging between 1 and 9\nTry again\n\n"; exit; } #We will define an ecological landscape with three parameters, including temperature, oxygen and food availability #We define an organism whith two main charactreistics, which are body size and speed my($student_number); print "\nIntroduce your student number: "; $student_number = ; chomp $student_number; my($out) = "Results" . "_$student_number"; print "\n*****Your evolved population will be sent to $out*****\n"; open(O, ">$out"); srand(time|$$); #my(@frequencies) = (0.05, 0.1, 0.15, 0.2, 0.25); my($i, $j) = (0,0); my(@population_values, @population); #while($i < scalar(@frequencies)) # { # my($num) = $frequencies[$i] * $pop_size; # my($valA) = $i + 1; my($valB) = 9 - $i; # my($k) = 0; # for($k = 0; $k < $num; $k++) # { # $population_values[$j] = $valA; # $j += 1; # $population_values[$j] = $valB; # $j += 1; # } # $i += 1; # } while($i < $pop_size) { # $population_values[$i] = $initial_organism; $population[$i] = $initial_organism; $i += 1; } #my(@sorted_population) = sort{$a <=> $b} @population_values; ###Now we are going to generate our organisms $i = 0; #my(@population); #while($i < $pop_size) # { # my($body_size, $move); # $body_size = $sorted_population[int(rand(scalar(@sorted_population)))]; # $move = $sorted_population[int(rand(scalar(@sorted_population)))]; # $population[$i] = $body_size . $move; # $i += 1; # } ###We are starting with the evolutionary dynamic now with the mutation process my($generations) = 0; my(@population_grown); my(%Frequencies); while($generations < $number_generations) { print "\rGeneration: " . ($generations + 1); my($number_mutations) = 0.1 * ($pop_size); my(@chosen_organisms); $i = 0; while($i < $number_mutations) { my($orden, $sense); $orden = int(rand(2)); $sense = int(rand(2)); if($sense < 2) { $sense = 1; }else { $sense = -1; } my($organism) = int(rand(scalar(@population))); if($orden < 2) { $orden = 0; }else { $orden = 1; } my($first, $second); $first = substr($population[$organism], 0, 1); $second = substr($population[$organism], 1, 1); if($orden == 0) { if(($first > 1) && ($first < 9)) { $first += $sense; }elsif($first == 1) { $first += 1; }elsif($first == 9) { $first -= 1; } $population[$organism] = $first . $second; }else { if(($second > 1) && ($second < 9)) { $second += $sense; }elsif($second == 1) { $second += 1; }elsif($second == 9) { $second -= 1; } $population[$organism] = $first . $second; } $i += 1; } ###Now each one of the organisms will compete based on their biological fitnesses and 90% of those with better fitness will pass to next generations and new organisms will duplicate until completing population size. my(%Fitness); @population_grown = (); $i = 0; $j = 0; my($k) = 0; ######################################################################################################################## ###Estimating Fitness of organisms in population $i = 0;my($sum_fitness) = 0; while($i < scalar(@population)) { $Fitness{$population[$i]} = fitness($population[$i], $temperature, $oxygen, $food); $sum_fitness += $Fitness{$population[$i]}; $i += 1; } ########################################################################################################################### ###First we make organisms replicate my($total_number_offspring) = $pop_size; my($aver_fitness) = $sum_fitness/(scalar(@population)); my(%pop_filter); my($num_individuals) = 0; my(@values, @sorted_values); foreach my $filt(keys(%Fitness)) { ### if($Fitness{$filt} > 0.4) ### { $pop_filter{$filt} = $Fitness{$filt}; $values[$num_individuals] = $Fitness{$filt}; $num_individuals += 1; ### } } @sorted_values = sort{$a <=> $b} @values; my($individuals_to_distribute) = $pop_size - $num_individuals; my($detected) = 0; foreach my $organism(keys(%pop_filter)) { if(($pop_filter{$organism} == $sorted_values[(scalar(@sorted_values)) - 1]) && ($detected == 0)) { for($j = 0; $j <= $individuals_to_distribute; $j++) { $population_grown[$k] = $organism; $k += 1; } $detected += 1; }else { for($j = 0; $j < 2; $j++) { $population_grown[$k] = $organism; $k += 1; } } } my($size_of_population) = scalar(@population_grown); ###Now, we make them mutate at the rate pre-especified by the user my($mutants) = int($mutation_rate * (scalar(@population_grown))); $i = 0; my($point_to_number, $Fit); while($i < $mutants) { do { my($random_number) = int(rand(scalar(@population_grown))); my($random_organism) = $population_grown[$random_number]; my($feature1, $feature2) = (substr($random_organism, 0, 1), substr($random_organism, 1, 1)); my($choice) = int(rand(10)); my($mutation); do { $mutation = int(rand(10)); }until($mutation != 0); if($choice <= 5) { $feature1 = $mutation; }else { $feature2 = $mutation; } $point_to_number = $random_number - 1; $population_grown[$random_number - 1] = $feature1 . $feature2; }until(($Fit = fitness($population_grown[$point_to_number], $temperature, $oxygen, $food)) > 0.4); $i += 1; } ############################################################################################################################################# ###Now, we will calculate the fitness of the organisms in the grown population $i = 0; my(%population_transferred); $sum_fitness = 0; my(@fitnesses); while($i < scalar(@population_grown)) { $Fitness{$population_grown[$i]} = fitness($population_grown[$i], $temperature, $oxygen, $food); $sum_fitness += $Fitness{$population_grown[$i]}; $fitnesses[$i] = $Fitness{$population_grown[$i]}; $i += 1; } my($population_transfer_next_generation) = $pop_size - ($bottleneck*$pop_size); my($pop) = 0; @population = (); my(%fitness_final_population); while($pop < $population_transfer_next_generation) { $population[$pop] = $population_grown[int(rand(scalar(@population_grown)))]; $fitness_final_population{$population[$pop]} = $Fitness{$population[$pop]}; $pop += 1; } my($add_rest_ind) = $pop_size - $population_transfer_next_generation; my($add) = 0; while($add < $add_rest_ind) { $population[$pop] = $population[int(rand(scalar(@population)))]; $pop += 1; $add += 1; } $add = 0; while($add < (scalar(@population))) { $fitness_final_population{$population[$add]} = $Fitness{$population[$add]}; $add += 1; } foreach my $fr(@population) { $Frequencies{$fr} = 0; } foreach my $fre(@population) { $Frequencies{$fre} += 1; } foreach my $FR(keys(%Frequencies)) { $Frequencies{$FR} /= (scalar(@population)); $Frequencies{$FR} *= 100; } ############################################################################################################################################# ####We are now going to print the frequency of the organisms with the highest fitness $generations += 1; } print "\n"; print O "Student: $student_number\n------------------------\n\n"; print O "Predicted Organism: $prediction\n"; print O "Initial organism: $initial_organism\nPopulation_size: $pop_size\nMutation Rates: $mutation_rate\nBottleneck to population size: $bottleneck\n"; print O "\nEnvironment Settings\n---------------------\n"; if($temperature < 3) { print O "Temperature ($temperature): Cold\n"; }elsif(($temperature >= 4) && ($temperature < 7)) { print O "Temperature ($temperature): mild\n"; }elsif($temperature >=7) { print O "Temperature ($temperature): Hot\n"; } if($oxygen < 3) { print O "Oxygen ($oxygen): rare\n"; }elsif(($oxygen >= 4) && ($oxygen < 7)) { print O "Oxygen ($oxygen): oxygen based atmosphere\n"; }elsif($oxygen >=7) { print O "Oxygen ($oxygen): High oxygen pressure\n"; } if($food < 3) { print O "Food resources ($food): scarse\n"; }elsif(($food >= 4) && ($food < 7)) { print O "Food resources ($food): medium\n"; }elsif($food >=7) { print O "food ($food): optimal environment with excess of resources\n"; } print O "\nFinal Population Frequencies:\n--------------------------------\n\n"; print O "Phenotype\t\tFrequency in the Population (%)\n---------\t\t--------------------------\n"; foreach my $Fr(sort{$Frequencies{$a} <=> $Frequencies{$b}} (keys(%Frequencies))) { print O "$Fr\t\t\t$Frequencies{$Fr}%\n"; } exit; ############################################################################################################################################# ##############################################################Subroutines#################################################################### sub fitness { my($organism_code, $temp, $oxy, $resources) = @_; my($body_size_code) = substr($organism_code, 0, 1); my($move_code) = substr($organism_code, 1, 1); my($fitnessfraction_food); if($resources < 4) { $fitnessfraction_food = (((2*$resources)/($body_size_code + (2*$resources)))+((2*$move_code)/((2*$move_code)+$resources)))/2; }else { $fitnessfraction_food = (((2*$body_size_code)/((2*$body_size_code) + $resources))+((2*$move_code)/((2*$move_code)+$resources)))/2; } my($fitnessfraction_Temp); if($temp < 4) { $fitnessfraction_Temp = (((2*$body_size_code)/((2*$body_size_code) + $temp))+((2*$move_code)/($temp + (2*$move_code))))/2; }else { $fitnessfraction_Temp = (((2*$temp)/($body_size_code + (2*$temp)))+((2*$temp)/($move_code + (2*$temp))))/2; } my($fitnessfraction_Ox) = (((2*$oxy)/($body_size_code + (2*$oxy)))+((2*$oxy)/($move_code+(2*$oxy))))/2; my($final_fitness) = ((2*$fitnessfraction_food)+(2*$fitnessfraction_Temp)+$fitnessfraction_Ox)/5; return $final_fitness; }