不知怎的,没有用Ruby分配一个类

时间:2010-02-08 02:57:16

标签: ruby class typechecking genetics

在运行时,我的代码经常会遇到方法mate的未定义方法错误。据我所知,Person在代码的执行过程中某个时候以某种方式滑过裂缝,并设法不分配allele

代码(免责声明,不是最佳格式化):

class Allele
  attr_accessor :c1, :c2

  def initialize(c1, c2)
    @c1 = c1
    @c2 = c2
  end

 #formats it to be readable
 def to_s
  c1.to_s + c2.to_s
 end

 #given Allele a
 def combine(a)
  pick = rand(4)
  case pick
   when 0
    Allele.new(c1,a.c1)
   when 1
    Allele.new(c1,a.c2)
   when 2
    Allele.new(c2,a.c1)
   when 3
    Allele.new(c2,a.c2)
  end
 end
end

class Person
 attr_accessor :allele, :male

 def initialize(allele,male)
    @allele = allele
  @male= male
  end

 #def self.num_people
  #@@num_people
 #end

 def to_s
  "Allele:" + allele.to_s + " | Male:" + male.to_s
 end

 def male
  @male
 end

 def allele
  @allele
 end

 def mate(p)
  if rand(2) == 0
   Person.new(allele.combine(p.allele),true)
  else
   Person.new(allele.combine(p.allele),false)
  end
 end
end

male_array = Array.new
female_array = Array.new
male_child_array = Array.new
female_child_array = Array.new

# EVENLY POPULATE THE ARRAY WITH 5 THAT PHENOTYPICALLY MANIFEST TRAIT, 5 THAT DON'T
# AND 5 GIRLS, 5 GUYS
pheno_dist = rand(5)
#make guys with phenotype
pheno_dist.times { male_array << Person.new(Allele.new(1,rand(2)),true) }
#guys w/o
(5-pheno_dist).times { male_array << Person.new(Allele.new(0,0),true) }
#girls w/ pheno
(5-pheno_dist).times { female_array << Person.new(Allele.new(1,rand(2)),false) }
#girls w/o
pheno_dist.times { female_array << Person.new(Allele.new(0,0),false) }

puts male_array
puts female_array
puts "----------------------"

4.times do
 #mates male with females, adding children to children arrays. deletes partners as it iterates
 male_array.each do
  male_id = rand(male_array.length) #random selection function. adjust as needed
  female_id = rand(female_array.length)
  rand(8).times do
   child = male_array[male_id].mate(female_array[female_id])
   if child.male
    male_child_array << child
   else
    female_child_array << child
   end
  end
  male_array.delete_at(male_id)
  female_array.delete_at(female_id)
 end

 #makes males male children, females female children, resets child arrays
 male_array = male_child_array
 female_array = female_child_array
 male_child_array = []
 female_child_array = []

 puts male_array
 puts female_array
 puts "----------------------"
end

什么立即出错?

2 个答案:

答案 0 :(得分:3)

正如egosys所说,你不应该从你正在迭代的数组中删除。

另一个问题是你的循环开始“4次做”。有时女性数组是空的,所以返回大小为0; rand(0)是随机浮点数&gt; = 0且&lt; 1.在空的female_array上使用它作为数组索引返回nil,然后传递给mate。

但不仅仅是错误。你使用每个人迭代men_array,然后随机挑选一个男性。这允许一些雄性不止一次交配;别人根本没有。同样,有些女性在每次迭代中都会交配并复制不止一次,有些则完全没有。这是你的意图吗?

让我们首先考虑将所有男性和女性保持在同一个阵列中。这将简化事情。但是,既然你确实需要找到所有的男性,有时甚至是所有的女性,我们会为此制定方法:

def males(population)
  population.find_all do |person|
    person.male?
  end
end

def females(population)
  population.find_all do |person|
    person.female?
  end
end

如果男性和女性应该随机配对,那么在生物学上会更准确,但没有人能够多次交配。这很简单:

def random_pairs(males, females)
  males.shuffle[0...females.size].zip(females.shuffle)
end

然后简单地再现人口:

def make_children(male, female)
  # return an array of children
end

def reproduce(population)
  children = []
  random_pairs(males(population), females(population)).each do |male, female|
    children << make_children(male, female)
  end
  children
end

具有这样的功能,然后进行4个循环的再现就像这样简单:

people = # ... generate your initial list of people of all sexe.
4.times do
  people = reproduce(people)
end

由于没有函数修改传递给它的参数,因此您不会遇到副作用的麻烦。

可以用OO风格完成更多工作,例如使人口成为一流的对象,并将“男性”,“女性”,“随机对”和“再现”等功能移入其中。我将把它作为读者的练习。

答案 1 :(得分:1)

从正在迭代的数组中删除每个都有未定义的行为。通常建议使用Array#delete_if,但我不确定在这种情况下你将如何使用它。