Filling individual cells in a grid

  • Thread starter Joop Van den tillaart
  • Start date

J

Joop Van den tillaart

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...

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

Advertisements

T

Todd Benson

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...

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
 
J

Joop Van den tillaart

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?
 
L

Logan Capaldo

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

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

Logan Capaldo

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

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

Advertisements

M

Morton Goldberg

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.

<code>
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 }
</code>

<result>
#<Grid:0x7b128 @width=2,
@grid=[Cell[0, [0, 0], , ], Cell[1, [1, 0], , ],
Cell[2, [0, 1], , ], Cell[3, [1, 1], , ]],
@height=2>
#<Grid:0x7b1a0 @width=2,
@grid=[Cell[0, [0, 0], 0, 0], Cell[1, [1, 0], 0, 1],
Cell[2, [0, 1], 0, 0], Cell[3, [1, 1], 0, 1]],
@height=2>
#<Grid:0x7b1a0 @width=2,
@grid=[Cell[0, [0, 0], 0, 0], Cell[1, [1, 0], 42, 1],
Cell[2, [0, 1], 0, 0], Cell[3, [1, 1], 42, 1]],
@height=2>
true
true
</result>

Regards, Morton
 
J

Joop Van den tillaart

Joop said:
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!

Attachments:
http://www.ruby-forum.com/attachment/233/testje.rb
 
M

Morton Goldberg

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?

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.

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

3. 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

<code>
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#[](x))).[](y)
# 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)
</code>
 
J

Joop Van den tillaart

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!
 
Ad

Advertisements

M

Morton Goldberg

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 :)
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??

<code>
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
</code>

Regards, Morton
 
M

Morton Goldberg

<code>
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
</code>

I've thought of a more efficient way.

<code>
zero_cells = grid.select { |cell| cell.cell_type == 0 }
n = zero_cells.size
k = (0.6 * n).round
(0...k).each { |i| zero_cells.cell_type = 2 }
(k...n).each { |i| zero_cells.cell_type = 3 }
</code>

Regards, Morton
 
J

Joop Van den tillaart

Morton said:
On Sep 6, 2007, at 4:47 PM, Morton Goldberg 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!
 
J

Joop Van den tillaart

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!

Attachments:
http://www.ruby-forum.com/attachment/265/testje.rb
 
Ad

Advertisements

M

Morton Goldberg

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
----------------------------

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
 
J

Joop Van den tillaart

Morton said:
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.


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...
 
Ad

Advertisements

M

Morton Goldberg

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?

<code>
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.cell_type = 2 }
(k...n).each { |i| zero_cells.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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top