From: w_a_x_man on
On Jul 14, 6:07 pm, w_a_x_man <w_a_x_...(a)yahoo.com> wrote:
> On Jul 14, 3:56 pm, Shawn W_ <sha...(a)internode.on.net> wrote:
>
> > I have a 2D Array. I have written a method
> > Array2D.adjacent(x,y,direction) that returns the adjacent cell to x,y in
> > the direction given. How do I deal with the boundary conditions without
> > receiving an error message.
>
> > For example, if I refer to a cell on the top row, and look north there
> > will be nothing there, and my program falls over.
>
> > I will be creating methods that run over the whole 2D array, replacing
> > things in random directions, so when it randomly hits a boundary I need
> > my program to ignore cells outside the boundary.
>
> > How can I do this? Thx
> > --
> > Posted viahttp://www.ruby-forum.com/.
>
> Yields nil if out of bounds:
>
> if ary[y]
>   ary[y][x]
> else
>   nil
> end

def get2d ary, x, y
if ary[y]
ary[y][x]
else
nil
end
end

ary = [
%w(Z Z Z Z),
%w(Z H H Z),
%w(Z X Z Z) ]

puts get2d( ary,2,1 )
puts get2d( ary,1,2 )
puts get2d( ary,3,3 )
puts get2d( ary,4,0 )

--- output ---
H
X
nil
nil
From: w_a_x_man on
On Jul 15, 5:49 am, w_a_x_man <w_a_x_...(a)yahoo.com> wrote:
> On Jul 14, 6:07 pm, w_a_x_man <w_a_x_...(a)yahoo.com> wrote:
>
> > On Jul 14, 3:56 pm, Shawn W_ <sha...(a)internode.on.net> wrote:
>
> > > I have a 2D Array. I have written a method
> > > Array2D.adjacent(x,y,direction) that returns the adjacent cell to x,y in
> > > the direction given. How do I deal with the boundary conditions without
> > > receiving an error message.
>
> > > For example, if I refer to a cell on the top row, and look north there
> > > will be nothing there, and my program falls over.
>
> > > I will be creating methods that run over the whole 2D array, replacing
> > > things in random directions, so when it randomly hits a boundary I need
> > > my program to ignore cells outside the boundary.
>
> > > How can I do this? Thx
> > > --
> > > Posted viahttp://www.ruby-forum.com/.
>
> > Yields nil if out of bounds:
>
> > if ary[y]
> >   ary[y][x]
> > else
> >   nil
> > end
>
> def get2d ary, x, y
>   if ary[y]
>     ary[y][x]
>   else
>     nil
>   end
> end
>
> ary = [
>   %w(Z Z Z Z),
>   %w(Z H H Z),
>   %w(Z X Z Z) ]
>
> puts get2d( ary,2,1 )
> puts get2d( ary,1,2 )
> puts get2d( ary,3,3 )
> puts get2d( ary,4,0 )
>
> --- output ---
> H
> X
> nil
> nil

def get2d ary, x, y
if ![x,y].include?(-1) and ary[y]
ary[y][x]
else
nil
end
end

ary = [
%w(Z Z Z Z),
%w(Z H H Z),
%w(Z X Z Z) ]

puts get2d( ary,2,1 )
puts get2d( ary,1,2 )
puts get2d( ary,3,3 )
puts get2d( ary,4,0 )
puts get2d( ary,4,-1 )

--- output ---
H
X
nil
nil
nil
From: Shawn W_ on
Dave Howell wrote:
> I was going to suggest using the 'case' statement instead of all those
> elsifs, but then I realized there was an even better way.
>
> class Array2D
>
> Delta=[[0,0], [0,1], [1,1], [1,0], [1,-1], [0,-1], [-1,-1], [-1,0],
> [-1,1]]
> attr_reader :width, :height
>
> def initialize(width, height)
> @width = width
> @height = height
> @data = Array.new(@width) { Array.new(@height) }
> end
>
> def [](x, y, z)
> deltaX, deltaY = *Delta[z]
> x = x + deltaX % @width
> y = y + deltaY
> @data[x][y] unless y<0 or y>@height
> end
>
> def []=(x, y, z, value)
> deltaX, deltaY = *Delta[z]
> x = (x + deltaX) % @width # modulus % allows wrapping
> y = y + deltaY
> @data[x][y] = value unless y<0 or y>(@height-1)
> end
> end
>
>
> Obviously the Delta array takes the place of the elsif chains in both []
> and []=. Also, :width and :height are defined with attr_reader, not
> attr_accessor, since it doesn't do any good at all to change those
> values after the array has been created.

Just be aware I'm a complete newb at programing and Ruby, so the more
elegant the code, the harder it is for me to read.

David, I tried your solution but it still falls over. Don't you need to
specify what happens if y<0 or y>(@height-1) is the case? I tried...

if y<0 or y>(@height-1)
nil
else
@data[x][y] = value
end

...but that didn't work? It falls over the moment it looks north from
the top row, or looks south east from the bottom row.

Also, I understand the line...

deltaX, deltaY = *Delta[z]

...is allocating the Delta array values to the deltaX and deltaY
variables based on the direction z given, but what is the * symbol
doing?

By the way, my program uses a hex grid, not a square grid - I posted a
square grid just for clarity. Adjacent cells directions change for odd
and even rows on a hex grid, but I think I can just create two Delta
arrays (Delta_even and Delta_odd) and modify the 1,0,-1 values for each,
then check for odd/eveness in y.

I have yet to nut out the other solution but will go through it later
today.
--
Posted via http://www.ruby-forum.com/.

From: Shawn W_ on
Okay, just found out that...

@data[x][y] unless y<0 or y>@height

...is the same as stating nil anyway, according to
http://www.themomorohoax.com/2009/05/21/when-to-use-nil-in-ruby-methods

The error I'm getting is...

undefined method `[]=' for nil:NilClass (NoMethodError)

...when the program hits this part of the code...

Array2D[x,y,1] = "X "

--
Posted via http://www.ruby-forum.com/.

From: Martin DeMello on
On Fri, Jul 16, 2010 at 11:11 AM, Shawn W_ <shawnw(a)internode.on.net> wrote:
> Okay, just found out that...
>
> @data[x][y] unless y<0 or y>@height
>
> ...is the same as stating nil anyway, according to
> http://www.themomorohoax.com/2009/05/21/when-to-use-nil-in-ruby-methods
>
> The error I'm getting is...
>
> undefined method `[]=' for nil:NilClass (NoMethodError)
>
> ...when the program hits this part of the code...
>
> Array2D[x,y,1] = "X "

The basic problem is that ruby doesn't have rectangular arrays, you
have to use arrays of arrays. So "array[y][x]" means "get array[y]
(which is itself an array) and take the xth element of that". So let's
say you initialize your array to [4][3]. Then you have

array = [
[nil, nil, nil], # array[0]
[nil, nil, nil], # array[1]
[nil, nil, nil], # array[2]
[nil, nil, nil] # array[3]
]

Now say you set array[1][2] = "X". Your new array is

array = [
[nil, nil, nil], # array[0]
[nil, nil, X ], # array[1]
[nil, nil, nil], # array[2]
[nil, nil, nil] # array[3]
]

you can do this either via

array[1][2] = "X"

or

a = array[1]
a[2] = "X"

So what happens when you go off the end of the array? Calling array[n]
where n is out of bounds will return nil, as expected...

array[1][100] # => nil

which is equivalent to

a = array[1] #=> [..., ..., ...]
a[100] #=> nil

But if you go out of bounds in the other dimension

array[100][1] # => undefined method `[]=' for nil:NilClass (NoMethodError)

because what you're in effect doing is

a = array[100] #=> nil
a[1] # => trying to call [] on nil, which raises the error

martin

First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5
Prev: Cpp Complier
Next: bug in TkComm::list?