- 1 class Population
- 2 def initialize(population_size, target)
- 3 @target = target
- 4
- 5 @population = []
- 6 population_size.times do
- 7 @population.push Individual.create_random(target, target.length)
- 8 end
- 9 end
- 10
- 11 def next_generation
- 12 target_length = @population.length
- 13 cull_population
- 14 repopulate(target_length).first.score
- 15 end
- 16
- 17 def cull_population
- 18 order_population
- 19 @population.each_index do |index|
- 20 if should_be_culled?(index)
- 21 @population.delete_at(index)
- 22 end
- 23 end
- 24 end
- 25
- 26 def repopulate(target_length)
- 27 order_population
- 28 growth = target_length - @population.length
- 29 babies = []
- 30 growth.times do
- 31 mate_a = find_mate(@population)
- 32 mate_b = find_mate_for(mate_a)
- 33 babies << mate_a.mate_with(mate_b)
- 34 end
- 35 @population += babies
- 36 end
- 37
- 38 def should_be_culled?(index)
- 39 rand(@population.length) <= index
- 40 end
- 41
- 42 def should_mate(index)
- 43 rand(@population.length) <= index
- 44 end
- 45
- 46 def find_mate(population)
- 47 while true do
- 48 population.each_index do |index|
- 49 if should_mate(index)
- 50 return population[index]
- 51 end
- 52 end
- 53 end
- 54 end
- 55
- 56 def find_mate_for(individual)
- 57 rest_of_pop = []
- 58 @population.each do |ind|
- 59 if ind != individual
- 60 rest_of_pop << ind
- 61 end
- 62 end
- 63 find_mate(rest_of_pop)
- 64 end
- 65
- 66 def order_population
- 67 @population.sort! do |a,b,|
- 68 a.score <=> b.score
- 69 end
- 70 end
- 71
- 72 def log
- 73 puts "-----"
- 74 @population.each do |individual|
- 75 puts individual.to_s
- 76 end
- 77 end
- 78
- 79 def log_best
- 80 puts @population.first.to_s
- 81 end
- 82 end
- 83
- 84 class Individual
- 85 def initialize(target, reproduction_system)
- 86 @target = target
- 87 @reproduction_system = reproduction_system
- 88 end
- 89
- 90 def self.create_random(target, output_length)
- 91 Individual.new(target, ReproductionSystem.create_random(output_length))
- 92 end
- 93
- 94 def score
- 95 score = 0
- 96 @reproduction_system.genes.each_index do |index|
- 97 score += (@target[index] - @reproduction_system.genes[index]).abs
- 98 end
- 99 score
- 100 end
- 101
- 102 def mate_with(mate)
- 103 @reproduction_system.mate_with(mate)
- 104 end
- 105
- 106 def be_mated_with(genetic_code)
- 107 Individual.new(@target, @reproduction_system.be_mated_with(genetic_code))
- 108 end
- 109
- 110 def to_s
- 111 @reproduction_system.to_s + " : " + score.to_s
- 112 end
- 113 end
- 114
- 115 class ReproductionSystem
- 116 attr_reader :genes
- 117 def initialize(genes)
- 118 @genes = genes
- 119 end
- 120
- 121 def self.random_gene_part
- 122 32 + rand(94)
- 123 end
- 124
- 125 def self.create_random(output_length)
- 126 genes = []
- 127 output_length.times do
- 128 genes.push(random_gene_part)
- 129 end
- 130 ReproductionSystem.new(genes)
- 131 end
- 132
- 133 def to_s
- 134 out = ''
- 135 @genes.each do |part|
- 136 out += part.chr
- 137 end
- 138 out
- 139 end
- 140
- 141 def mate_with(mate)
- 142 mate.be_mated_with(@genes)
- 143 end
- 144
- 145 def be_mated_with(genetic_code)
- 146 length = @genes.length
- 147 a_half = genetic_code.slice(0, length/2)
- 148 b_half = @genes.slice(length/2,length-1)
- 149 genes = a_half + b_half
- 150 genes[rand(length)] = ReproductionSystem.random_gene_part
- 151
- 152 ReproductionSystem.new(genes)
- 153 end
- 154 end
- 155
- 156 population = Population.new(100, "Hello World")
- 157 population.order_population
- 158 population.log
- 159 i=0
- 160 while(population.next_generation>0) do
- 161 puts "generation " + (i+=1).to_s
- 162 population.log_best
- 163 end