Skip to content

Instantly share code, notes, and snippets.

@jnaglick
Created December 24, 2013 20:18
Show Gist options
  • Save jnaglick/8117451 to your computer and use it in GitHub Desktop.
Save jnaglick/8117451 to your computer and use it in GitHub Desktop.
flower.rb - breed flowers with a genetic algorithm - john naglick - 2013
class Flower
class Stem
module Bits
LENGTH = 3
WIDTH = 2
OUTER_COLOR = 8
INNER_COLOR = 8
TOTAL = 21 # TODO compute this
end
attr_accessor :length, :width, :outer_color, :inner_color
def initialize binary_s = nil
if binary_s == nil
r = Random.new
self.length = r.rand 2 ** Bits::LENGTH
self.width = r.rand 2 ** Bits::WIDTH
self.outer_color = r.rand 2 ** Bits::OUTER_COLOR
self.inner_color = r.rand 2 ** Bits::INNER_COLOR
else
self.length = binary_s[0, Bits::LENGTH].to_i 2
self.width = binary_s[Bits::LENGTH, Bits::WIDTH].to_i 2
self.outer_color = binary_s[Bits::LENGTH + Bits::WIDTH, Bits::OUTER_COLOR].to_i 2
self.inner_color = binary_s[Bits::LENGTH + Bits::WIDTH + Bits::OUTER_COLOR, Bits::INNER_COLOR].to_i 2
end
end
def to_s
"length: #{length} width: #{width} ocolor: #{outer_color} icolor: #{inner_color}"
end
def to_binary_s
length.to_s(2).rjust(Bits::LENGTH, '0') + width.to_s(2).rjust(Bits::WIDTH, '0') + outer_color.to_s(2).rjust(Bits::OUTER_COLOR, '0') + inner_color.to_s(2).rjust(Bits::INNER_COLOR, '0')
end
end
class Petals
module Bits
LENGTH = 3
WIDTH = 2
OUTER_COLOR = 8
INNER_COLOR = 8
AMOUNT = 4
TOTAL = 25 # TODO compute this
end
attr_accessor :length, :width, :outer_color, :inner_color, :amount
def initialize binary_s = nil
if binary_s == nil
r = Random.new
self.length = r.rand 2 ** Bits::LENGTH
self.width = r.rand 2 ** Bits::WIDTH
self.outer_color = r.rand 2 ** Bits::OUTER_COLOR
self.inner_color = r.rand 2 ** Bits::INNER_COLOR
self.amount = r.rand 2 ** Bits::AMOUNT
else
self.length = binary_s[0, Bits::LENGTH].to_i 2
self.width = binary_s[Bits::LENGTH, Bits::WIDTH].to_i 2
self.outer_color = binary_s[Bits::LENGTH + Bits::WIDTH, Bits::OUTER_COLOR].to_i 2
self.inner_color = binary_s[Bits::LENGTH + Bits::WIDTH + Bits::OUTER_COLOR, Bits::INNER_COLOR].to_i 2
self.amount = binary_s[Bits::LENGTH + Bits::WIDTH + Bits::OUTER_COLOR + Bits::INNER_COLOR, Bits::AMOUNT].to_i 2
end
end
def to_s
"length: #{length} width: #{width} ocolor: #{outer_color} icolor: #{inner_color} amount: #{amount}"
end
def to_binary_s
length.to_s(2).rjust(Bits::LENGTH, '0') + width.to_s(2).rjust(Bits::WIDTH, '0') + outer_color.to_s(2).rjust(Bits::OUTER_COLOR, '0') + inner_color.to_s(2).rjust(Bits::INNER_COLOR, '0') + amount.to_s(2).rjust(Bits::AMOUNT, '0')
end
end
attr_accessor :stem, :petals
def initialize binary_s = nil
if binary_s == nil
self.stem = Stem.new
self.petals = Petals.new
else
self.stem = Stem.new binary_s[0, Stem::Bits::TOTAL]
self.petals = Petals.new binary_s[Stem::Bits::TOTAL, Petals::Bits::TOTAL]
end
end
def to_s
"stem: [#{stem}] petals: [#{petals}]"
end
def to_binary_s
stem.to_binary_s + petals.to_binary_s
end
end
def random_gen size
gen = []
(1..size).each do
gen.push Flower.new
end
gen
end
def pick gen
selected = {}
gen.each_with_index do |g, i|
selected[i] = false
end
while true
gen.each_with_index do |g, i|
puts "#{i}: [#{selected[i]}] #{g}"
end
puts '>> TOGGLE ONES YOU WANT (\'q\' when done)'
input = gets.chomp
break if input == 'q'
selected[input.to_i] = !selected[input.to_i]
end
gen.values_at *selected.select{|k,v|v}.keys
end
def breed_gen flowers, mutation_rate = 0.20
gen = []
flowers.product(flowers).select{|i|i[0]!=i[1]}.each do |flower1, flower2| # everything is bred with everything else, but not itself
total_bits = Flower::Stem::Bits::TOTAL + Flower::Petals::Bits::TOTAL
breed_pt = 0
breed_pt = (Random.rand total_bits) while (breed_pt < (0.2 * total_bits).to_i || breed_pt > (0.8 * total_bits).to_i)
new_flower_binary_s = flower1.to_binary_s[0, breed_pt] + flower2.to_binary_s[breed_pt, total_bits]
if Random.rand < mutation_rate
(1..5).each do
mutate_pt = Random.rand total_bits
new_flower_binary_s[mutate_pt] = new_flower_binary_s[mutate_pt] == '0' ? '1' : '0'
end
end
gen.push Flower.new new_flower_binary_s
end
gen
end
# init 10 random flowers
# loop:
# display them
# score them (user selects favorites)
# breed + mutate
gen_i = 0
gen = random_gen 10
while true
puts "*** GENERATION #{gen_i} ***"
puts gen
puts '>> KEEP GOING?'
input = gets.chomp
break if input == 'q'
picked = pick gen
puts "you picked #{picked.count} that time"
gen = breed_gen picked
gen_i += 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment