-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenetic_algorithm.rb
More file actions
128 lines (105 loc) · 2.45 KB
/
genetic_algorithm.rb
File metadata and controls
128 lines (105 loc) · 2.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
class Genes
attr_reader :generation, :quiz
def initialize(gene_count = 10, quiz_length = 10)
@gene_count = gene_count
@quiz_length = quiz_length
@generation = 1
@quiz = Quiz.new(quiz_length)
begin
@genes = Array.new(gene_count) { Gene.new(quiz_length) }
self.mark()
self.sort()
end until self.max < quiz_length
end
def start
while self.max < @quiz.length
yield(self)
self.next_genration()
self.mark()
self.sort()
end
yield(self)
end
def mark
@genes.each { |g| g.score = @quiz.mark(g) }
end
def sort
@genes.sort! { |a, b| b.score <=> a.score }
end
def next_genration
@generation += 1
gene1, gene2 = self.breed(@genes[0], @genes[1])
@genes[@genes.length - 2] = gene1
@genes[@genes.length - 1] = gene2
end
def breed(parent1, parent2)
child1 = Gene.new(@quiz_length)
child2 = Gene.new(@quiz_length)
cross_position = rand(@quiz_length - 1)
@quiz_length.times do |i|
if i < cross_position
child1[i] = parent1[i]
child2[i] = parent2[i]
else
child1[i] = parent2[i]
child2[i] = parent1[i]
end
end
mutation_position = rand(@quiz_length)
child1[mutation_position] = rand(3) if mutation_position < @quiz_length
mutation_position = rand(@quiz_length)
child2[mutation_position] = rand(3) if mutation_position < @quiz_length
return child1, child2
end
def max
@genes[0].score
end
def min
@genes[(@genes.length - 1)].score
end
def average
@genes.inject(0) { |x, g| x + g.score } / @genes.size
end
def [](index)
@genes[index]
end
end
class Gene
attr_accessor :score
attr_reader :length, :answers
def initialize(length)
@length = length
@answers = Array.new(@length) { rand(3) }
end
def [](index)
@answers[index]
end
def []=(index, value)
@answers[index] = value
end
def to_s
"[" + @answers.join(',') + "]"
end
end
class Quiz < Gene
def mark(answers)
score = 0
@length.times { |i| score += 1 if @answers[i] == answers[i] }
score
end
end
#--------------------------------
Genes.new.start do |genes|
puts "Generation: #{genes.generation}"
puts "Max: #{genes.max}, Average: #{genes.average}"
puts "A #{genes.quiz}"
puts "--------------------------------"
10.times do |i|
puts "#{i} #{genes[i]} #{genes[i].score}"
end
# manual
#break if gets =~ /x/
# auto
sleep 1
puts
end