Skip to content

Instantly share code, notes, and snippets.

@smazhara
Created January 13, 2011 19:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smazhara/778428 to your computer and use it in GitHub Desktop.
Save smazhara/778428 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'rubygems'
require 'open-uri'
class SpaceCat
attr_reader :weight, :limbs, :color
attr_accessor :fitness
def initialize(*traits)
@weight, @limbs, @color, @fitness = *traits
end
def hexcolor
('%6s' % color.to_s(16)).gsub(' ', '0')
end
def self.random
new rand(1000), rand(100), rand(0xffffff)
end
def mutate
@weight += rand(10 * 2 + 1) - 10
@weight = [[@weight, 1000].min, 1].max
@limbs += rand(1 * 2 + 1) - 1
@limbs = [[@limbs, 100].min, 0].max
@color += rand(167772 * 2 + 1) - 167772
@color = [[@color, 0xffffff].min, 0].max
end
def clone
SpaceCat.new weight, limbs, color, fitness
end
def to_s
'[' + [weight, limbs, hexcolor, fitness].join(' ') + ']'
end
def <=>(other)
self.fitness.to_i <=> other.fitness.to_i
end
end
class Galaxy < Struct.new :name
def teleport(cats)
traits = {}
%w(weight limbs hexcolor).each do |trait|
traits[trait.to_sym] = cats.map{|cat|cat.send trait}.join(',')
end
url = "http://spacecats.heroku.com/galaxies/#{name}" +
"?batch=true" +
"&weight=#{traits[:weight]}" +
"&limbs=#{traits[:limbs]}" +
"&color=#{traits[:hexcolor]}"
fitnesses = open(url).read.split(',')
#puts "#{url}: #{fitnesses.join(',')}"
cats.each_index do |i|
cats[i].fitness = fitnesses[i]
end
end
def self.all
@@all ||= open("http://spacecats.heroku.com/galaxies").read.split(',').
map{|name| new(name)}
end
end
class Exploration < Struct.new :galaxy, :cats, :cycles, :cutoff
def run
cycles.times do |trip|
galaxy.teleport(cats)
self.cats.sort!
# eliminate bottom @cutoff underperformers
self.cats.slice!(0, cutoff)
# clone top @cutoff superperformers
clones = cats.slice(-cutoff, cutoff).map{|cat| cat.clone}
self.cats += clones
puts "#{trip}: #{best_cat}: " +
cats.slice(-20,20).map{|cat|cat.fitness}.join(',')
cats.each{|cat| cat.mutate}
end
end
def best_cat
@best_cat ||= cats.last.dup
@best_cat = [@best_cat, cats.last].max.dup
end
end
galaxy = ARGV
size = 100
trips = 1000
crew = size.times.map{SpaceCat.random}
gal = Galaxy.new galaxy
e = Exploration.new gal, crew, trips, crew.size / 10
e.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment