2017-05-12 16 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