0

在运行时,我的代码经常遇到方法未定义的方法错误mate。据我所知,aPerson不知何故在代码执行的某个时候从裂缝中溜走了,并且设法没有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

什么立即看起来不对劲?

4

2 回答 2

3

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

另一个问题是在你的循环中开始“4.times do”。有时女性数组为空,因此返回大小 0;rand(0) 是一个 >= 0 且 < 1 的随机浮点数。将其用作空 female_array 上的数组索引会返回 nil,然后将其传递给 mate。

但错误远不止于此。您正在使用 each 遍历male_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 样式中完成更多工作,例如将 Population 设为一等对象并将函数“males”、“females”、“random_pairs”和“reproduce”移入其中。我将把它作为练习留给读者。

于 2010-02-08T03:37:13.177 回答
1

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

于 2010-02-08T03:14:11.397 回答