2
\$\begingroup\$

Custom class Image takes a 2-D array of 0's and 1's upon initialization. Method transform returns a modified array by modifying 0's adjacent to a 1, such that

[[0,0,0],
 [0,1,0],
 [0,0,0]]

returns

[[0,1,0],
 [1,1,1],
 [0,1,0]]

I've been working on method blur(n), which outputs an array that has been transformed n times, such that n=3 changes

[[0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,1,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0],
 [0,0,0,0,0,0,0,0,0]]

into

[[0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 1, 0, 0, 0, 0]
 [0, 0, 0, 1, 1, 1, 0, 0, 0]
 [0, 0, 1, 1, 1, 1, 1, 0, 0]
 [0, 1, 1, 1, 1, 1, 1, 1, 0]
 [0, 0, 1, 1, 1, 1, 1, 0, 0]
 [0, 0, 0, 1, 1, 1, 0, 0, 0]
 [0, 0, 0, 0, 1, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 0, 0, 0, 0, 0, 0, 0, 0]]

Right now my solution to blur(n) works, by first creating a new Image object, transforming and then transforming additional instances of Image an additional (n-1) times. I've been getting errors if I try to apply blur without instantiating a new Image and transforming it — the transform method is not available to class Array. How could I go about applying transform iteratively without having to instantiate Image inside the class?

class Image
  attr_accessor :arr

  def initialize(arr)
    @arr = arr
  end

  def transform 
    cloned = self.arr.map(&:clone)

    #scan original array for 1; map crosses into clone if found
    self.arr.each.with_index do |row, row_index|
      row.each.with_index do |cell, col|
        if cell == 1
          cloned[row_index][col+1] = 1 unless col+1 >= row.length #copy right
          cloned[row_index+1][col] = 1 unless row_index+1 >= cloned.length # copy down
          cloned[row_index][col-1] = 1 unless col.zero? # copy left
          cloned[row_index-1][col] = 1 unless row_index.zero? #copy up
        end
      end
    end
    cloned
  end

  def blur(n) 
    blurred = Image.new(self).arr.transform
    (n-1).times do 
      blurred = Image.new(blurred).transform
    end
    blurred
  end

end

image = Image.new([[0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,1,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0]])

image.blur(3)

#returns...
# [[0, 0, 0, 0, 0, 0, 0, 0, 0], 
#  [0, 0, 0, 0, 1, 0, 0, 0, 0], 
#  [0, 0, 0, 1, 1, 1, 0, 0, 0], 
#  [0, 0, 1, 1, 1, 1, 1, 0, 0], 
#  [0, 1, 1, 1, 1, 1, 1, 1, 0], 
#  [0, 0, 1, 1, 1, 1, 1, 0, 0], 
#  [0, 0, 0, 1, 1, 1, 0, 0, 0], 
#  [0, 0, 0, 0, 1, 0, 0, 0, 0], 
#  [0, 0, 0, 0, 0, 0, 0, 0, 0], 
#  [0, 0, 0, 0, 0, 0, 0, 0, 0], 
#  [0, 0, 0, 0, 0, 0, 0, 0, 0], 
#  [0, 0, 0, 0, 0, 0, 0, 0, 0]]
\$\endgroup\$
2
\$\begingroup\$

I assume you are trying to do something like:

def blur(n) 
  blurred = Image.new(self).arr.transform
  (n-1).times do 
    blurred = blurred.transform
  end
  blurred
end

And getting an error like:

`block in blur': undefined method `transform' for #<Array:0x00000002d51ba8>

The reason is that transform is a instance method of Image, which is why you need to convert back into an image before calling it.

There are a couple of way this can be handled. I've chosen to make transform a static method that only works on arrays. The instance methods transform and blur call the static method as needed

class Image
  attr_accessor :arr

  def initialize(arr)
    @arr = arr
  end

  def transform
    result = Image.arr_transform(@arr)
    Image.new(result)
  end

  def self.arr_transform(array) 
    cloned = array.map(&:clone)

    #scan original array for 1; map crosses into clone if found
    array.each.with_index do |row, row_index|
      row.each.with_index do |cell, col|
        if cell == 1
          cloned[row_index][col+1] = 1 unless col+1 >= row.length #copy right
          cloned[row_index+1][col] = 1 unless row_index+1 >= cloned.length # copy down
          cloned[row_index][col-1] = 1 unless col.zero? # copy left
          cloned[row_index-1][col] = 1 unless row_index.zero? #copy up
        end
      end
    end
    cloned
  end

  def blur(n)
    blurred = @arr
    (n).times do 
      blurred = Image.arr_transform(blurred)
    end
    Image.new(blurred)
  end

end

Testing:

image = Image.new([[0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,1,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0],
                   [0,0,0,0,0,0,0,0,0]])

require 'pp'
pp image.blur(3)

Returns:

#<Image:0x00000002e9fb40
 @arr=
  [[0, 0, 0, 0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 1, 0, 0, 0, 0],
   [0, 0, 0, 1, 1, 1, 0, 0, 0],
   [0, 0, 1, 1, 1, 1, 1, 0, 0],
   [0, 1, 1, 1, 1, 1, 1, 1, 0],
   [0, 0, 1, 1, 1, 1, 1, 0, 0],
   [0, 0, 0, 1, 1, 1, 0, 0, 0],
   [0, 0, 0, 0, 1, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 0, 0, 0, 0],
   [0, 0, 0, 0, 0, 0, 0, 0, 0]]>
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.