Prev: Cpp Complier
Next: bug in TkComm::list?
From: Martin DeMello on 18 Jul 2010 04:43 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 18 Jul 2010 23:47 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 19 Jul 2010 03:43 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 21 Jul 2010 01:00 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 22 Jul 2010 01:50
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} |