AI::Evolve::Befunge::Population - manage a population


    use aliased 'AI::Evolve::Befunge::Population' => 'Population';
    use AI::Evolve::Befunge::Util qw(v nonquiet);

    $population = Population->new();

    while(1) {
        my $gen  = $population->generation;
        nonquiet("generation $gen\n");


This manages a population of Befunge AI critters.

This is the main evolution engine for AI::Evolve::Befunge. It has all of the steps necessary to evolve a population and generate the next generation. The more times you run this process, the more progress it will (theoretically) make.


There are two constructors, depending on whether you want to create a new population, or resume a saved one.


    my $population = Population->new(Generation => 50);

Creates a Population object. The following arguments may be specified (none are mandatory):

    Blueprints - a list (array reference) of critters.   (Default: [])
    Generation - the generation number.                   (Default: 1)
    Host - the hostname of this Population.      (Default: `hostname`)



Load a savefile, allowing you to pick up where it left off.


These methods are intended to be the normal user interface for this module. Their APIs will not change unless I find a very good reason.



Rehashes the config file, pulls various values from there. This is common initializer code, shared by new() and load(). It defines the values for the following items:




Determines (through a series of fights) the basic fitness of each critter in the population. The fight routine (see the "double_match" method in is called a bunch of times in parallel, and the loser dies (is removed from the list). This is repeated until the total population has been reduced to 25% of the "popsize" setting.



Bring the population count back up to the "popsize" level, by a process of sexual reproduction. The newly created critters will have a combination of two previously existing ("winners") genetic makeup, plus some random mutation. See the "crossover" and "mutate" methods, below. There is also a one of 5 chance a critter will be resized, see the "crop" and "grow" methods, below.



Send and receive critters to/from other populations. This requires an external networking script to be running.

Exported critters are saved to a "migrate-$HOST/out" folder. The networking script should broadcast the contents of any files created in this directory, and remove the files afterwards.

Imported critters are read from a "migrate-$HOST/in" folder. The files are removed after they have been read. The networking script should save any received critters to individual files in this folder.



Write out the current population state. Savefiles are written to a "results-$HOST/" folder. Also calls "cleanup_intermediate_savefiles" to keep the results directory relatively clean, see below for the description of that method.


The APIs of the following methods may change at any time.



Overwrite a section of the blueprint's code with trash. The section size, location, and the trash are all randomly generated.


    $population->crossover($blueprint1, $blueprint2);

Swaps a random chunk of code in the first blueprint with the same section of the second blueprint. Both blueprints are modified.



Possibly (1 in 10 chance) reduce the size of a blueprint. Each side of the hypercube shall have its length reduced by 1. The preserved section of the original code will be at a random offset (0 or 1 on each axis).



Possibly (1 in 10 chance) increase the size of a blueprint. Each side of the hypercube shall have its length increased by 1. The original code will begin at the origin, so that the same code executes first.



Keeps the results folder mostly clean. It preserves the milestone savefiles, and tosses the rest. For example, if the current generation is 4123, it would preserve only the following:

savefile-1 savefile-10 savefile-100 savefile-1000 savefile-2000 savefile-3000 savefile-4000 savefile-4100 savefile-4110 savefile-4120 savefile-4121 savefile-4122 savefile-4123

This allows the savefiles to accumulate and allows access to some recent history, and yet use much less disk space than they would otherwise.



Possibly export some critters. if the result of rand(13) is greater than 10, than the value (minus 10) number of critters are written out to the migration network.



Look on the migration network for incoming critters, and import some if we have room left. To prevent getting swamped, it will only allow a total of (Popsize*1.5) critters in the array at once. If the number of incoming migrations exceeds that, the remainder will be left in the Migrator receive queue to be handled the next time around.


    my $trash = $population->new_code_fragment($length, $density);

Generate $length bytes of random Befunge code. The $density parameter controls the ratio of code to whitespace, and is given as a percentage. Density=0 will return all spaces; density=100 will return no spaces.


    my ($c1, $c2) = $population->pair(map { 1 } (@population));
    my ($c1, $c2) = $population->pair(map { $_->fitness } (@population));

Randomly select and return two blueprints from the blueprints array. Some care is taken to ensure that the two blueprints returned are not actually two copies of the same blueprint.

The @fitness parameter is used to weight the selection process. There must be one number passed per entry in the blueprints array. If you pass a list of 1's, you will get an equal probability. If you pass the critter's fitness scores, the more fit critters have a higher chance of selection.


    my $generation = $population->generation();

Fetches or sets the population's generation number to the given value. The value should always be numeric.

When set, as a side effect, rehashes the config file so that new generational overrides may take effect.