2017-05-12 6 views
0

ConwayのGame of Lifeの2次元配列を使って作業していて、各セルの「近傍」の合計を計算しようとすると、ゼロ値によってブロックされてしまいます。配列の前で「プット」が含まれるが、私が試したの選択肢のどれもが私に100%を与えない場合合計を得るには、配列内で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は、ほとんどの結果を得ているようです。私はreduce(:+)、inject、.to_i、reject(nil値を取り除く)などを試みました。

ここには何が欠けていますか?

エラー:world.rb:35:block (2 levels) in neighbor_count': undefined method []」ゼロのために:NilClass(NoMethodError)

線35は

答えて

1

ゼロ値のみ症状】.compact.sum上記ラインであるです病気。症状を治療しないで、問題を取り除く!あなたが配列境界に違反しているということです。

.each_with_indexは、最初から最後までのすべてのインデックスを列挙します。したがって、最後のインデックスにidx + 1があると、この範囲外の状況が発生します。最初にidx - 1を入力すると、エラーではなく予期しない値が生成され、計算に影響します。幸運をデバッグする。 :)

あなたのコードにいくつかのガードチェックを入れて、決して外れないようにしてください。


ただ、絶対に明確にし、問題がgrid[idx + 1][idx2]がnilであると、あなたの計算を台無しということではありません。 grid[idx + 1]はnilです!そして当然、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

あなたは別の方法に隣人の列挙を移動することができ:座標xyこのコードを考えると

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 

は、単純に(有効な)隣人が得られます。ブロックが与えられていなければ、最初の行は列挙子を返します。あなたもオフセットを生成するためにrepeated_permutationを利用することができる代わりに、ネストされたuptoループの

、:しかし

[-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 
関連する問題