From: Martin DeMello on
On Sat, Jul 17, 2010 at 8:14 AM, Dave Howell
<groups.2009a(a)grandfenwick.net> wrote:
> OK, let's try this from the top. {grin} Here's some fresh new code:

Looks good :)

> Note that @data is no longer defined as "Array.new(@width) { Array.new(@height) }". I think I copied that from your code? but discovered that it gave each row the SAME array, so that changing [1][3] caused every cell in that column to have the same value. Useless! Not the first time that feature of Ruby (and it is a feature, wacky though it sometimes seems) has surprised me.

That shouldn't have happened - the block passed to Array.new should
create a new array every time it's called.

irb(main):001:0> a = Array.new(5) { Array.new(3) }
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil], [nil, nil,
nil], [nil, nil, nil]]

irb(main):002:0> a[1][2] = 0
=> 0

irb(main):003:0> a
=> [[nil, nil, nil], [nil, nil, 0], [nil, nil, nil], [nil, nil, nil],
[nil, nil, nil]]

irb(main):004:0> b = Array.new(5, Array.new(3))
=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil], [nil, nil,
nil], [nil, nil, nil]]

irb(main):005:0> b[1][2] = 0
=> 0

irb(main):006:0> b
=> [[nil, nil, 0], [nil, nil, 0], [nil, nil, 0], [nil, nil, 0], [nil, nil, 0]]

martin

From: Shawn W_ on
Dave Howell wrote:
> OK, let's try this from the top. {grin} Here's some fresh new code:

Thx again - very instructive.

I have managed to get the capping working in isolation as per the
following code:

---

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
attr_accessor :cell_content

def initialize(width, height, cell_content)
@width = width
@height = height
@data = Array.new(@height) {Array.new(@width){|i| cell_content} }
end

def [](x, y, z)
deltaX, deltaY = *Delta[z]
x = (x + deltaX) % @width
y = (y + deltaY)
@data[y][x] unless y<0 or y>(@height-1)
end

def []=(x, y, z, value)
deltaX, deltaY = *Delta[z]
x = (x + deltaX) % @width # modulus % allows wrapping
y = (y + deltaY)
@data[y][x] = value unless y<0 or y>(@height-1)
end

def display
@height.times {|rownum| print(@data[rownum].join(" ") + "\n")};nil
end

end

a=Array2D.new(10,5,"X")
m = rand(10)
n = rand(5)
a[m,n,0] = "A"
a[m,n,1] = "H"
a[m,n,2] = "H"
a[m,n,3] = "H"
a[m,n,4] = "A"
a[m,n,5] = "A"
a[m,n,6] = "A"
a[m,n,7] = "A"
a[m,n,8] = "A"
puts a.display

---

However, it still falls over when I try to insert the above into my main
program, as below:

---

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(@height) {Array.new(@width) {|i|"X"}}
end

def [](x, y, z)
deltaX, deltaY = *Delta[z]
x = (x + deltaX) % @width
y = (y + deltaY)
@data[y][x] unless y<0 or y>(@height-1)
end

def []=(x, y, z, value)
deltaX, deltaY = *Delta[z]
x = (x + deltaX) % @width # modulus % allows wrapping
y = (y + deltaY)
@data[y][x] = value unless y<0 or y>(@height-1)
end

def display
@height.times {|rownum| print(@data[rownum].join(" ") + "\n")};nil
end

end


class World < Array2D

attr_reader :size

def initialize(size)
@rows = size
@cols = @rows * 2
@world = Array2D.new(@cols, @rows)
end

def populate_array_cells_with_hash
(0...(a)rows).each do |b|
(0...(a)cols).each do |a|
@world[a,b,0] = {
"hex_col_no" => a,
"hex_row_no" => b,
"hex_id_A" => "X ",
"hex_id_B" => nil,
"hex_id_C" => nil,
"hex_id_D" => nil,
"hex_id_E" => nil,
}
end
end
end

def insert_teleporting_square
m = rand(@cols)
n = rand(@rows)
@world[m,n,0]["hex_id_A"] = "A "
@world[m,n,1]["hex_id_A"] = "H "
@world[m,n,2]["hex_id_A"] = "H "
@world[m,n,3]["hex_id_A"] = "H "
@world[m,n,4]["hex_id_A"] = "A "
@world[m,n,5]["hex_id_A"] = "A "
@world[m,n,6]["hex_id_A"] = "A "
@world[m,n,7]["hex_id_A"] = "A "
@world[m,n,8]["hex_id_A"] = "A "
end

def print_world(type)
(0...(a)rows).each do |b|
puts
(0...(a)cols).each do |a|
print @world[a,b,0][type]
end
end
end

end

first_world = World.new(5)
first_world.populate_array_cells_with_hash
first_world.insert_teleporting_square
first_world.print_world("hex_id_A")
puts

---

It falls over when it hits one of these two lines:
@world[m,n,1]["hex_id_A"] = "H "
@world[m,n,4]["hex_id_A"] = "A "

With error as before:
undefined method `[]=' for nil:NilClass (NoMethodError)

What my program does is generate an array, then populates each cell of
that array with a hash. It looks like when it tries to access the hash
values outside the array boundary it runs into problems? Do I need
another method inside the Array2D class to deal with hash access? If so,
how can this be done? If not, can anyone see any other reason for the
error?

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

From: Robert Klemme on
2010/7/14 Shawn W_ <shawnw(a)internode.on.net>:
> 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

Did anybody suggest modulo operator so far? I only glanced over
replies so I might actually have overseen something. Anyway, you can
see it working here:

irb(main):001:0> a = Array.new(10){|row| Array.new(10) {|col|
"#{row},#{col}"}};nil
=> nil
irb(main):002:0> a.size
=> 10
irb(main):003:0> a[0].size
=> 10

irb(main):012:0> 15.times {|i| printf "%2d %p %p\n",i,a[0][i % 10],a[i % 10][0]}
0 "0,0" "0,0"
1 "0,1" "1,0"
2 "0,2" "2,0"
3 "0,3" "3,0"
4 "0,4" "4,0"
5 "0,5" "5,0"
6 "0,6" "6,0"
7 "0,7" "7,0"
8 "0,8" "8,0"
9 "0,9" "9,0"
10 "0,0" "0,0"
11 "0,1" "1,0"
12 "0,2" "2,0"
13 "0,3" "3,0"
14 "0,4" "4,0"
=> 15

Kind regards

robert


--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

From: Shawn W_ on
Shawn W_ wrote:
> Dave Howell wrote:
>> OK, let's try this from the top. {grin} Here's some fresh new code:
>
> What my program does is generate an array, then populates each cell of
> that array with a hash. It looks like when it tries to access the hash
> values outside the array boundary it runs into problems? Do I need
> another method inside the Array2D class to deal with hash access? If so,
> how can this be done? If not, can anyone see any other reason for the
> error?

I think I got it. I did away with storing my cell data in a hash; rather
I will put an array in each cell of the 2D array, and add another
parameter to the def [] and def []= methods to access it.

So:
new_2Darray = Array2D(10,5)
new_2Darray[3,1,4,0] = "H"
printing out the array gives:
X X X X X X X X X X
X X X H X X X X X X
X X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X

column = 3
row = 1
cell index = 4 (5th element of the array sitting in that cell of the 2D
array)
direction = 0

I'm not sure how efficient this will be, or whether it will be
restrictive in using some of the default Ruby methods, but it's
certainly makes my code very neat.

Thx again for everyone's help.


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

From: Dave Howell on

On Jul 18, 2010, at 1:43 , Martin DeMello wrote:

> That shouldn't have happened - the block passed to Array.new should
> create a new array every time it's called.

That's what I thought, too.

And now I can't duplicate the effect.

OK, I'm very puzzled. {shrug}


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