2017-05-12 18 views
0

使用二维数组处理康威的生命游戏版本,当尝试计算每个单元格的“邻居”总数时,我一直被零值阻塞。如何将数组中的nil转换为0来获得总和?

def neighbor_count 
     grid.each_with_index do |row, idx| 
      row.each_with_index do |column, idx2| 
       [grid[idx - 1][idx2 - 1], grid[idx - 1][idx2], grid[idx - 1][idx2 + 1], 
       grid[idx][idx2 - 1], grid[idx][idx2], grid[idx][idx2 + 1], 
       grid[idx + 1][idx2 - 1], grid[idx + 1][idx2], grid[idx + 1][idx2 + 1] 
       ].compact.sum 

      end 
     end 
    end 

.compact似乎产生最的结果,如果包括在阵列前面的“看跌期权”,但没有的我已经试过的选项给我100%。我试过减少(:+),注入,.to_i,拒绝(摆脱零值),等等。

这里缺少什么?

错误:world.rb:35:在block (2 levels) in neighbor_count': undefined method []”为零:NilClass(NoMethodError)

第35行是上述] .compact.sum线

回答

1

零值仅是的症状疾病。不要治疗症状,摆脱问题!这是你违反数组边界。

.each_with_index枚举从第一个到最后一个的所有索引。因此最后一个索引的idx + 1将触发这种超出界限的情况。而第一个idx - 1会产生一个意想不到的值,而不会产生错误,这会影响您的计算。祝你好运调试。 :)

在你的代码中加入一些警戒检查,以确保你永远不会超出界限。


只是要绝对清楚,问题不在于grid[idx + 1][idx2]是零,弄糟你的计算。那是grid[idx + 1]是零!当然,你不能这样做nil[idx2]。这是错误。

+0

谢谢。我明白了,因为它会产生零值。有关如何有效排除任何超出边界的坐标的建议? –

+0

@JeremyFlanagan:是的,有些人会做得很好。 –

+0

@JeremyFlanagan:这是我在_years_之前编码的生活游戏。所以没有判断的代码https://gist.github.com/stulentsev/0e25ae7b079466412a87de26fc4f11be :) –

1

用1层边界声明你的网格,那么不会有任何需要额外添加if/else子句,也可以使用方向向量来访问循环中的邻居。

#let say you want to delare 4x4 grid, declare grid of (row+2, col+2) 
row, col, default_value = 4, 4, 0 
grid = Array.new(row+2){Array.new(col+2,default_value)} 

# store direction vectors dx and dy 
dx = [-1, -1, -1, 0, 1, 1, 1, 0, 0] 
dy = [-1, 0, 1, 1, 1, 0, -1, -1, 0] 
(1..row).each do |i| 
    (1..col).each do |j| 
     puts (0..8).reduce(0) { |sum, k| sum + grid[i + dx[k]][j + dy[k]]} 
end 
+0

如果有人使用填充,它必须添加在字段的_all_边上,否? –

+1

@SergioTulentsev感谢先生指出这一点,很好的发现,编辑了答案。 – aqfaridi

1

您可以在邻居的枚举移到单独的方法:

def each_neighbor(x, y) 
    raise IndexError unless within_bounds?(x, y) 
    return enum_for(:each_neighbor, x, y) unless block_given? 
    (y - 1).upto(y + 1) do |j| 
    (x - 1).upto(x + 1) do |i| 
     next unless within_bounds?(i, j) # skip out of bounds cells 
     next if i == x && j == y   # skip middle cell 
     yield grid[i][j] 
    end 
    end 
end 

定坐标xy这个代码只会产生(有效)的邻居。如果没有给出块,第一行返回一个枚举器。

代替嵌套upto循环,你也可以利用repeated_permutation产生偏移:

[-1, 0, 1].repeated_permutation(2) do |dx, dy| 
    next unless within_bounds?(x + dx, y + dy) 
    next if dx.zero? && dy.zero? # skip middle cell 
    yield grid[x + dx][y + dy] 
end 
然而

更重要的是,返回一个枚举器允许您链方法从Enumerable,如:

def grid 
    [[1, 2, 1], 
    [2, 3, 2], 
    [1, 2, 1]] 
end 

each_neighbor(1, 1).sum #=> 12 
each_neighbor(1, 1).count #=> 8 

each_neighbor(0, 0).sum #=> 7 
each_neighbor(0, 0).count #=> 3