On Jul 15, 2010, at 14:45 , Shawn W_ wrote:

> Dave Howell wrote:
>> I was going to suggest using the 'case' statement instead of all =
those=20
>> elsifs, but then I realized there was an even better way.
>>=20
>> class Array2D
>>=20
>>  Delta=3D[[0,0], [0,1], [1,1], [1,0], [1,-1], [0,-1], [-1,-1], =
[-1,0],=20
>> [-1,1]]
>>  attr_reader :width, :height
>>=20
>>  def initialize(width, height)
>>    @width =3D width
>>    @height =3D height
>>    @data =3D Array.new(@width) { Array.new(@height) }
>>  end
>>=20
>>  def [](x, y, z)
>>    deltaX, deltaY =3D *Delta[z]
>>    x =3D x + deltaX % @width
>>    y =3D y + deltaY
>>    @data[x][y] unless y<0 or y>@height
>>  end
>>=20
>>  def []=3D(x, y, z, value)
>>    deltaX, deltaY =3D *Delta[z]
>>    x =3D (x + deltaX) % @width # modulus % allows wrapping
>>    y =3D y + deltaY
>>    @data[x][y] =3D value unless y<0 or y>(@height-1)
>>  end
>> end
>>=20
>>=20
>> Obviously the Delta array takes the place of the elsif chains in both =
[]=20
>> and []=3D. Also, :width and :height are defined with attr_reader, not=20=

>> attr_accessor, since it doesn't do any good at all to change those=20
>> values after the array has been created.
>=20
> Just be aware I'm a complete newb at programing and Ruby, so the more=20=

> elegant the code, the harder it is for me to read.

Well, for what it's worth, it could have been 'eleganted' far more =
unreadably than this. {grin}


> David, I tried your solution but it still falls over. Don't you need =
to=20
> specify what happens if y<0 or y>(@height-1) is the case? I tried...
>=20
>    if y<0 or y>(@height-1)
>        nil
>      else
>        @data[x][y] =3D value
>    end
>=20
> ...but that didn't work? It falls over the moment it looks north from=20=

> the top row, or looks south east from the bottom row.

As you've discovered, "unless" is the same as "if not", and=20

	(result) if (test)=20

is the same as

	if (test) then
		(result)
	else
		nil
	end

Note that you can also do=20

	myAnswer =3D if (test) then
			(result)
		else
			nil
		end

which is the same as

	if (test) then
		myAnswer =3D (result)
	else
		myAnswer =3D nil
	end

So, putting it all together, you could say

	myAnswer =3D (result) if (test)

If (test) is true, myAnswer will get (result). If it's not true, it will =
get nil.


>=20
> Also, I understand the line...
>=20
> deltaX, deltaY =3D *Delta[z]
>=20
> ...is allocating the Delta array values to the deltaX and deltaY=20
> variables based on the direction z given, but what is the * symbol=20
> doing?

Splitting the array into pieces. Except that when I tested it just now, =
it's apparently unnecessary. I didn't know that!

> By the way, my program uses a hex grid, not a square grid - I posted a=20=

> square grid just for clarity. Adjacent cells directions change for odd=20=

> and even rows on a hex grid, but I think I can just create two Delta=20=

> arrays (Delta_even and Delta_odd) and modify the 1,0,-1 values for =
each,=20
> then check for odd/eveness in y.

I've worked with hex grids before. You don't need a pair of arrays, you =
can model a hex grid with a normal 2-d array.=20

Hex: 0=3Dsame, 1 =3D upper right, 2 =3D right, 3 =3D lower right, 4 =3D =
lower left, 5 =3D left, 6 =3D upper left, with [0,0] in the upper left =
of the grid.

	Delta=3D[[0,0], [0.5,-1], [1,0], [0.5,1], [-0.5,1], [-1,0], =
[-0.5,-1]]

If you're in an odd row (y%2 =3D=3D1), then add 0.75 to x. If you're in =
an even row, add 0.25. Then drop the decimal part to get your x,y =
values.

	x =3D (x + deltaX + 0.25 + (0.5 if y%2 =3D=3D1).to_f).to_i

The ".to_f" is needed because if y%2 is NOT =3D=3D 1, the result is =
"nil", and you can't add nil to a number, so the .to_f converts 'nil' to =
"0.0".=20

Imagine each co-ordinate is a brick in a normal wall of bricks. Every =
other row is slid over a bit, so you have to zig-zag in order to go =
'straight down" the wall. You might need to play around with it to see =
why it works . . .

> The error I'm getting is...
>=20
> undefined method `[]=3D' for nil:NilClass (NoMethodError)
>=20
> ...when the program hits this part of the code...
>=20
> Array2D[x,y,1] =3D "X "

I don't consider myself a hard-core Ruby expert, so I wouldn't be =
surprised if there was a bug in my code. On the other hand, I'll bet =
part of the problem is that you appear to be confusing a Class with an =
instance. You can't (or shouldn't normally be able to) assign anything =
to "Array2D".=20

	myTerritory =3D Array2D.new
	myTerritory[3,4,1] =3D "X "

	enemyTerritory =3D Array2D.new
	enemyTerritory[2,3,1] =3D "X "


Now, it *is* possible to define Array2D in a way that would let you say =
something like Array2D[x,y,1] =3D "X " and have it work, but we haven't =
done that here and I don't think you want to. There are . . . =
ramifications . . .=