<repo_name>matpalm/dead-simple-ga<file_sep>/member.rb

class Array

  def randomize
    clear
    GENE_SIZE.times { self << random_gene_value }
    self
  end

  def random_gene_value
    (rand()*10).to_i
  end

  def fitness
    inject { |a,v| a+v }
  end

  def mutate
    point_wise_mutation
    inversion_mutation
  end

  def point_wise_mutation
    return unless rand() < 0.01
    self[rand(size)] = random_gene_value
  end

  def inversion_mutation
    return unless rand() < 0.01
    from, to = rand(size), rand(size)
    from, to = to, from if from > to    
    splice = self.slice(from,to-from).reverse
    (from...to).each { |idx| self[idx] = splice.shift }
  end

  def crossover_with other    
    self.zip(other).collect { |p| rand()>0.5 ? p[0] : p[1]}
  end
  
end

def random_member
  [].randomize  
end

<file_sep>/main.rb
GENE_SIZE = 30
POPN_SIZE = 20

require 'member'
require 'population'

p = Population.new
5000.times { p.epoch }
<file_sep>/population.rb

class Population

  def initialize
    @members = []
    POPN_SIZE.times { @members <<  random_member }
  end

  def epoch
    calculate_fitness
    breed_next_gen
    mutate_members
    #inject_random_member
    output_members
  end

  def calculate_fitness
    @fitness = @members.collect {|m| m.fitness }
    @total_fitness = @fitness.inject{|a,v| a+v}
    puts "@fitness=#{@fitness.inspect} @total_fitness=#{@total_fitness}"
  end

  def breed_next_gen
    next_gen_members = []
    (POPN_SIZE/2).times do
      parent1 = select_member
      parent2 = select_member
      next_gen_members << parent1.crossover_with(parent2)
      next_gen_members << parent2.crossover_with(parent1)
    end
    @members = next_gen_members
  end

  def select_member
    selection_value = rand(@total_fitness)    
    @fitness.each_with_index do |v,i|
      selection_value -= v
      return @members[i] if selection_value<=0
    end
    raise "fail!"
  end

  def mutate_members
    @members.each {|m| m.mutate }
  end

  def inject_random_member
    @members.first.randomize
  end
  
  def output_members
    @members.each {|m| puts m.inspect }
  end

end
