Filling individual cells in a grid

Hi guys,

can someone please lend me a hand in this. I have a piece of code that
generates a grid like structure. All the cells in this grid now have 2
properties namely a celltype and a cell distance (to cells with type 1).

For now the code can only define celltypes to rows and columns. I need
to add a piece of code that will let me define celltypes to individual
cells. Does anyone know how I can achieve this and what pieces of code I
need to add?

I could really use a hand of someone more experienced in Ruby as I am.
Thanks in advance!

Greets tillaart36…

On 9/3/07, Joop Van den tillaart [email protected] wrote:

I could really use a hand of someone more experienced in Ruby as I am.
Thanks in advance!

Greets tillaart36…

Attachments:
http://www.ruby-forum.com/attachment/218/testgrid3.rb

With your current code…

grid[1,1].type = 3
grid[1,1].distance_road = 5

Todd

Is there no one else who can help me out a bit?

Thanks…

On 9/3/07, Joop Van den tillaart [email protected] wrote:

Is there no one else who can help me out a bit?

Thanks…


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

it’s been less than three hours since you posted your original
question. Patience is a wonderful thing.

With your current code…

grid[1,1].type = 3
grid[1,1].distance_road = 5

Todd

Hey,

thanks for your help. I was working the code myself and found another
way of individual filling but your way is much cleaner I think. Is there
also a way of filling a group of cells (which is not a full column or a
full row)?

All the cells with type 1 are are already defined and then I need to
fill like 60% of the remaining cells with type 3 and the other 40% with
type 4. I think I need to add a method to the code which lets me do that
but I’m don’t have much experience with ruby so I don’t know how to do
this…

Can anybody help me further on this?

On 9/3/07, Joop Van den tillaart [email protected] wrote:

Is there no one else who can help me out a bit?

Thanks…


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

it’s been less than three hours since you posted your original
question. Patience is a wonderful thing.

On Sep 3, 2007, at 8:40 AM, Joop Van den tillaart wrote:

Is there no one else who can help me out a bit?

OK, I’ll make some suggestions.

  1. I think you could make your life a lot easier if you gave your
    cell objects more info about where they live.
  2. I suggest you fill @grid with cells during initialization.
  3. I suggest you include Enumerable in your Grid class. Then you only
    have to define Grid#each to get map, collect, and whole more for free.
class Cell attr_accessor :type, :distance_road attr_reader :i def initialize(grid, i) @my_grid = grid @i = i end def xy @i.divmod(@my_grid.width).reverse end def inspect "Cell[#{@i}, #{xy.inspect}, #{type}, #{distance_road}]" end end class Grid include Enumerable attr :width, :heigh def initialize(width, height) @grid = Array.new(width * height) { |i| Cell.new(self, i) } @width = width @height = height end def [](x, y) raise IndexError.new("Index (#{x}, #{y}) out of range") \ if x < 0 || y < 0 || x >= @width || y >= @width @grid[y * width + x] end def []=(x, y, value) raise IndexError.new("Index (#{x}, #{y}) out of range") \ if x < 0 || y < 0 || x >= @width || y >= @width @grid[y * width + x] = value end def each @grid.each { |cell| yield cell } end end

Now you can do all kinds of neat things.

g = Grid.new(2, 2)
p g
g.map { |cell| cell.type = 0; cell.distance_road = cell.i % 2 }
p g
h = g.select { |cell| cell.distance_road == 1 }
h.each { |cell| cell.type = 42 }
p g
p g.any? { |cell| cell.type == 42 }
p g.all? { |cell| g[*cell.xy] == cell }

# # # true true

Regards, Morton

Joop Van den tillaart wrote:

Wow, thanks for your help…

Im trying it out right now…

Hey all you guys…

me and someone of my university have set up a new way of generating the
grid.

For now it generates a grid of 20x20 with 2 columns and 1 row filled
with celltype 1. The other cells are set to value 0.

I want the remaining cells with value 0 to be divided in say 60% type 2
and the remaining 40% (of the remaining 0 cells) to be valued as type 3.

Does anyone know how to do this in a neat way (from a programmers point
of view) and if so can anyone share some techniques with me?

See the attachment for the new generating of the grid.

Thanks in advance!

Wow, thanks for your help…

Im trying it out right now…

On Sep 6, 2007, at 7:44 AM, Joop Van den tillaart wrote:

of view) and if so can anyone share some techniques with me?
Are you asking for a random 40% of the cells to be assigned type 3
state while the remaining 60% is assigned type 2? Or is there some
other criterion?

See the attachment for the new generating of the grid.

I looked at your code and here are some comments:

!. I think you got x and y interchanged. You won’t see the problem as
long you are using square grids. So try it with 20-wide by 15-high
grid. The way you have set it up, it is impossible to traverse the
grid from top to bottom, right-to-left, with Grid#each, which is
something you are going to want to do. Compare print_field_values to
print_grid in the code below.

  1. Look at how I rewrote Grid#[] below.

  2. Since you are using OpenStructs to model your cells, I can’t see
    how you going to write a useful Grid#[]=, but the one you have now
    can’t possibly work.

Regards, Morton

require 'ostruct'

class Grid
include Enumerable

def initialize(width, height)

@grid = Array.new(width) do |x|

Array.new(height) do |y|

OpenStruct.new(:x => x, :y => y, :grid => self)

end

end

end

def initialize(width, height)
@grid = Array.new(height) do |row|
Array.new(width) do |col|
OpenStruct.new(:x => col, :y => row, :grid => self)
end
end
end

def width
@grid.first.size
end

def height
@grid.size
end

def width

@grid.size

end

def height

@grid.first.size

end

def each
@grid.each do |row|
row.each do |cell|
yield cell
end
end
end

def [](x, y)
@grid[y][x] if @grid[y]
end

def [](x, y)

return @grid[x][y] if @grid[x]

nil

end

This can’t work – super[x][y] means (self.(Object#)).

which can’t possibly be what is wanted.

def []=(x, y, value)

if @grid[x] && @grid[x][y]

super[x][y] = value

else

raise IndexError.new

end

end

def print_field_values(field_name = :cell_type)
each_with_index do |cell, i|
print "%02d " % cell.send(field_name)
puts if i % width == width - 1
end
end

end

def print_grid(grid, field_name = :cell_type)
grid.height.times do |y|
grid.width.times do |x|
print "%02d " % grid[x,y].send(field_name)
end
puts
end
end

def calculate_distance(grid, field_name)
updated = true
while updated do
updated = false
grid.each do |cell|
for x in (cell.x - 1)…(cell.x + 1)
for y in (cell.y - 1)…(cell.y + 1)
neighbour = grid[x, y]
next if neighbour.nil? || cell == neighbour || x<0 || y< 0
if neighbour.send(field_name) && (cell.send
(field_name).nil? || neighbour.send(field_name) + 1 < cell.send
(field_name))
cell.send(field_name.to_s + “=”, neighbour.send
(field_name) + 1)
updated = true
end
end
end
end
end
end

grid = Grid.new(20, 15)
grid.each { |cell| cell.cell_type = 0 }
grid.height.times { |y| grid[19,y].cell_type = 1 }
grid.height.times { |y| grid[9,y].cell_type = 1 }
grid.width.times { |x| grid[x,9].cell_type = 1 }
grid.each do |cell|
if cell.cell_type == 1
cell.distance_road = 0
cell.locked = true
end
end

grid.each do |cell|
if cell.cell_type == 0
cell.cell_type = 2
end
end

print_grid(grid, :cell_type)
puts
grid.print_field_values(:cell_type)

hi thanks for your help,

im not sure what you meant with your comments but i will look into
them…again thanks…

And my goal for filling the cells is as you say…the remaining cells
just have to be filled with say 60% type 2 en the remaining 40% of cells
with type 3. This can be done random or just first 60% type2 and the
other type 3.

When this is completed i need to make an algorithm that starts swapping
celltypes depending on neighbour cells and distances to other cells…i
won’t go to deep into this but it doesn’t matter how the cells in the
first stage are filled…just the types 1 are on a own place because
they characterize a road which is laid in before the algorithm starts
swapping…

So can anyone tell how to define the first 60% as type 2 and the
remaining cells with type 0 to type 3??

thanks!

On Sep 6, 2007, at 11:38 AM, Joop Van den tillaart wrote:

hi thanks for your help,

You’re welcome.

im not sure what you meant with your comments but i will look into
them…again thanks.

I’m trying to keep you from shooting yourself in the foot :slight_smile:

won’t go to deep into this but it doesn’t matter how the cells in the
first stage are filled…just the types 1 are on a own place because
they characterize a road which is laid in before the algorithm starts
swapping…

So can anyone tell how to define the first 60% as type 2 and the
remaining cells with type 0 to type 3??

require 'ostruct'

class Grid
include Enumerable

def initialize(width, height)
@grid = Array.new(height) do |row|
Array.new(width) do |col|
OpenStruct.new(:x => col, :y => row, :grid => self)
end
end
end

def width
@grid.first.size
end

def height
@grid.size
end

def each
@grid.each do |row|
row.each do |cell|
yield cell
end
end
end

def [](x, y)
@grid[y][x] if @grid[y]
end

def print_field_values(field_name = :cell_type)
each_with_index do |cell, i|
print "%02d " % cell.send(field_name)
puts if i % width == width - 1
end
end

end

grid = Grid.new(20, 15)
grid.each { |cell| cell.cell_type = 0 }
grid.height.times { |y| grid[19,y].cell_type = 1 }
grid.height.times { |y| grid[9,y].cell_type = 1 }
grid.width.times { |x| grid[x,9].cell_type = 1 }
grid.each do |cell|
if cell.cell_type == 1
cell.distance_road = 0
cell.locked = true
end
end

zero_cells = grid.select { |cell| cell.cell_type == 0 }
n = (0.6 * zero_cells.size).round
zero_cells[0…n-1].each { |cell| cell.cell_type = 2 }
zero_cells[n…-1].each { |cell| cell.cell_type = 3 }
grid.print_field_values

Regards, Morton

On Sep 6, 2007, at 4:47 PM, Morton G. wrote:

zero_cells = grid.select { |cell| cell.cell_type == 0 } n = (0.6 * zero_cells.size).round zero_cells[0..n-1].each { |cell| cell.cell_type = 2 } zero_cells[n..-1].each { |cell| cell.cell_type = 3 } grid.print_field_values

I’ve thought of a more efficient way.

zero_cells = grid.select { |cell| cell.cell_type == 0 } n = zero_cells.size k = (0.6 * n).round (0...k).each { |i| zero_cells[i].cell_type = 2 } (k...n).each { |i| zero_cells[i].cell_type = 3 }

Regards, Morton

Morton G. wrote:

On Sep 6, 2007, at 4:47 PM, Morton G. wrote:

I’ve thought of a more efficient way.

Hey man,

again thanks for your help…as you will have noticed I’m not an expert
at ruby but I’m sure appreciating the help I get from you people…

Let me have a go with this code and see where it gets me…

Thanks again!

Hi guys,

i’m back with a new problem with my grid:

I have three celltypes:

1 = road
2 = housing
3 = green

Each type has a table where preference scores are stored regarding the
adjacency of other celltypes…these are stored in the hash ATable…

Now i have to code an algorithm that iterates over all cells and which
calculates adjacency scores…I have made a word document where i try to
explain what the algorithm needs to do. Me and a teacher have coded two
things for this:


def scoreA(cell)

here the algorithm has to be placed

end

The adjacency score of one cell needs to be calculated within this
method…


for cell1 in grid
for cell2 in grid

# compare cell1 with cell2

next if cell1 == cell2
next if cell1.locked || cell2.locked

# calculate score for two cells together
a_before = scoreA(cell1) + scoreA(cell2)

# swap cells
cell1.cell_type, cell2.cell_type = cell2.cell_type, cell1.cell_type

# calculate score for two cells together
a_after = scoreA(cell1) + scoreA(cell2)

# if last score is lower or even as the score before swap, then swap 

cells back to first situation
if a_after <= a_before
cell1.cell_type, cell2.cell_type = cell2.cell_type, cell1.cell_type
end
end
end

the whole swapping procedure should be in this code above…

Now I think i have to design the code which calculates the score of one
cell regarding its neighbouring cells with the help of the ATable hash.
This piece of code has to be in the method scoreA(cell)…

but I’m really stuck in how to do this. Besides that I realize that it
is a long story / question I ask so maybe it won’t get much reply, but
on the other hand if someone is interested in helping me out a bit I
would be very grateful…

Anyways I have attached my ruby file and a word document in which i
tried to explain the procedure of the algorithm…

Thanks in advance!

and the word document…

On Sep 11, 2007, at 4:57 AM, Joop Van den tillaart wrote:

Each type has a table where preference scores are stored regarding the
def scoreA(cell)

# compare cell1 with cell2

# calculate score for two cells together

end

I see one problem with the above code – it walks the entire
adjacency matrix. It would be better to redesign it to walk only on
either the upper or the lower triangular sub-matrix. Then you only
need to deal with each distinct cell pairing once.

Attachments:

Sorry. There is no way that I’m going to open a Word document of
unknown content on my computer.

Regards, Morton

Morton G. wrote:

On Sep 11, 2007, at 4:57 AM, Joop Van den tillaart wrote:

Each type has a table where preference scores are stored regarding the
def scoreA(cell)

# compare cell1 with cell2

# calculate score for two cells together

end

I see one problem with the above code – it walks the entire
adjacency matrix. It would be better to redesign it to walk only on
either the upper or the lower triangular sub-matrix. Then you only
need to deal with each distinct cell pairing once.

Attachments:

Sorry. There is no way that I’m going to open a Word document of
unknown content on my computer.

Regards, Morton

I noticed that too…it doesnt look to the surrounding cells on a
distance of 1 cell…it walks through all the cells…how do i change
the code so it will only take into account surrounding cells on distance
1?

And euhm…why do you worry about the word document? It’s just a brief
explanation of what the algorithm should do…I’m sure you have your
reasons for not opening it (but I don’t see them :D)…anyways thanks
for your help so far…

part b

On Sep 11, 2007, at 7:57 AM, Joop Van den tillaart wrote:

Regards, Morton

I noticed that too…it doesnt look to the surrounding cells on a
distance of 1 cell…it walks through all the cells…how do i change
the code so it will only take into account surrounding cells on
distance
1?

require 'ostruct'

class Grid
include Enumerable

def initialize(width, height)
   @grid = Array.new(height) do |row|
      Array.new(width) do |col|
         OpenStruct.new(:x => col, :y => row, :grid => self)
      end
   end
end

def width
   @grid.first.size
end

def height
   @grid.size
end

def each
   @grid.each do |row|
      row.each do |cell|
         yield cell
      end
   end
end

def [](x, y)
   @grid[y][x] if @grid[y]
end

def print_field_values(field_name = :cell_type)
   each_with_index do |cell, i|
      print "%02d " % cell.send(field_name)
      puts if i % width == width - 1
   end
end

def each_with_neighbor
   each { |cell| cell.visited = false }
   each do |cell|
      next if cell.locked
      neighbors(cell).each { |other| yield cell, other }
      cell.visited = true
   end
end

def neighbors(cell)
   result = []
   x, y = cell.x, cell.y
   (-1..1).each do |dx|
      (-1..1).each do |dy|
         begin
            next if dx == 0 && dy == 0
            _cell = cell.grid[x+dx, y+dy]
            result << _cell unless _cell.locked || _cell.visited
         rescue IndexError
            next
         end
      end
   end
   result
end

end

I’m setting up a small grid here to reduce the amount of output.

grid = Grid.new(5, 4)
grid.each { |cell| cell.cell_type = 0 }
grid.height.times { |y| grid[4, y].cell_type = 1 }
grid.height.times { |y| grid[2, y].cell_type = 1 }
grid.width.times { |x| grid[x, 3].cell_type = 1 }
grid.each do |cell|
if cell.cell_type == 1
cell.distance_road = 0
cell.locked = true
end
end

zero_cells = grid.select { |cell| cell.cell_type == 0 }
n = zero_cells.size
k = (0.6 * n).round
(0…k).each { |i| zero_cells[i].cell_type = 2 }
(k…n).each { |i| zero_cells[i].cell_type = 3 }
grid.print_field_values

puts

Example showing how to use each_with_neighbor. Shows where your code

would go. Also prints outs what cell pairs get processed.

grid.each_with_neighbor do |cell, other|
# # calculate score for two cells together
# a_before = scoreA(cell) + scoreA(other)
# # swap cells
# cell.cell_type, other.cell_type = other.cell_type, cell.cell_type
# # calculate score for two cells together
# a_after = scoreA(cell) + scoreA(other)
# # if last score is lower or even as the score before swap,
# # then swap cells back to first situation
# if a_after <= a_before
# cell.cell_type, other.cell_type = other.cell_type,
cell.cell_type
# end
p [[cell.x, cell.y, cell.cell_type],
[other.x, other.y, other.cell_type]]
end

And euhm…why do you worry about the word document? It’s just a brief
explanation of what the algorithm should do…I’m sure you have your
reasons for not opening it (but I don’t see them :D)…anyways thanks
for your help so far…

There are viruses that attach themselves to Word documents and which
spread when someone downloads the document and opens it on uninfected
computer.

If your explanation is brief, why not post it as part of a message
(not an attachment)? If you do, I’m not sure I’ll implement it for
you. I’m beginning to think that I’ve been doing too much of your
school work for you, and it would be better you did more of it
yourself. But then again I might or at least give some pointers or
someone else may be willing to help you.

Regards, Morton