Just do:
Array.new(N) { Array.new(M, -1) }
instead of:
Array.new(N, Array.new(M, -1))
Read the documentation:
Case 1:
new(size) {|index| block }
an array of the given size is created. Each element in this array is created by passing the element’s index to the given block and storing the return value.
Example:
ary_new_without_block = Array.new(3) { [] }
ary_new_without_block.map(&:object_id) # => [75888070, 75888060, 75888050]
Look at the object ids, all are different, which ensures that all the inner array objects are different. Thus if you change one any inner array object, changes will not be seen in all element array(s):
ary_new_without_block[0] << 2
ary_new_without_block # => [[2], [], []]
Case 2:
new(array)
creates a copy of the array passed as a parameter (the array is generated by calling #to_ary on the parameter).
Example:
ary_new_block = Array.new(3,[])
ary_new_block.map(&:object_id) # => [75888980, 75888980, 75888980]
Look at the object ids, all are same, which ensures that all the inner array objects are not different. Thus if you change one inner array object, changes will be seen in all elements:
ary_new_block[0] << 2
ary_new_block # => [[2], [2], [2]]
You choose the second case, thus you didn't get the output as you were looking for. But the first case will help you to reach to your goal.