I'm embarassed to post this..
Don't be! We're all learning from each other, just at different levels.
Let me make some general comments below.
The Cell class has this
def hasneighbour
@neighbour +=1
end
Okay, first I think the name of this method needs some work. Usually,
we use a form like has_neighbour, to make things a little easier on our
eyes.
Then we need to look at the name itself. Is has_neighbour answering a
question? That's what I expect from that name. It looks to me like
it's changing something and that's certainly not what I expect from
that name.
This all may sound silly, but eventually you'll need to read your code
too and we need to read it now to help, so you want to keep it as self
documenting as possible.
# determine rules for the fate of any cells
def fate
case @neighbour
when 2
# no change to the alive or dead status
when 3
# cell springs into life
@isalive = true
else
# all other conditions the cell dies
@isalive = false
end
# reset the neighbour count for the next generation
@neighbour = 0
return @isalive
end
To me a full blown class seems a bit overkill for a cell. What are we
really tracking about each cell? One piece of information right? Does
it have a critter in it or not?
Because of that, I would probably just put a 2D array in my world class
and fill it with spaces and Xs. Pretty much any calculation needs to
be done from that level anyway, since neighboring cells are always
involved, so it seems like this cell level abstraction just gets in the
way.
The World class has this monster
def calcGeneration
# work through a grid, identifying all live cells
# and incrementing the neighbour count of their neighbours
# the faster we can weed out entries wih no live cell - the
# faster this algorithm works
@world.each_index {
|row|
@world[row].each_index { |col|
# - ----- now what
# for each row and column
if @world[row][col].isalive
case row
# first row
when 0
case col
# first column
when 0
@world[row][col+1].hasneighbour
@world[row+1][col].hasneighbour
@world[row+1][col+1].hasneighbour
# middle columns
when 1..(@x-2)
@world[row][col-1].hasneighbour
@world[row][col+1].hasneighbour
@world[row+1][col].hasneighbour
@world[row+1][col+1].hasneighbour
@world[row+1][col-1].hasneighbour
# RHS columns
else
@world[row][col-1].hasneighbour
@world[row+1][col-1].hasneighbour
@world[row+1][col].hasneighbour
end
# all middle rows
when 1..(@y -2)
case col
when 0
@world[row-1][col].hasneighbour
@world[row-1][col+1].hasneighbour
@world[row][col+1].hasneighbour
@world[row+1][col].hasneighbour
@world[row+1][col+1].hasneighbour
when 1..(@x-2)
@world[row-1][col-1].hasneighbour
@world[row-1][col].hasneighbour
@world[row-1][col+1].hasneighbour
@world[row][col-1].hasneighbour
@world[row][col+1].hasneighbour
@world[row+1][col-1].hasneighbour
@world[row+1][col].hasneighbour
@world[row+1][col+1].hasneighbour
else
@world[row-1][col-1].hasneighbour
@world[row-1][col].hasneighbour
@world[row][col-1].hasneighbour
@world[row+1][col].hasneighbour
@world[row+1][col-1].hasneighbour
end
else # bottom row
case col
when 0
@world[row-1][col].hasneighbour
@world[row-1][col+1].hasneighbour
@world[row][col+1].hasneighbour
when 1..(@x-2)
@world[row-1][col-1].hasneighbour
@world[row-1][col].hasneighbour
@world[row-1][col+1].hasneighbour
@world[row][col-1].hasneighbour
@world[row][col+1].hasneighbour
else
@world[row-1][col-1].hasneighbour
@world[row-1][col].hasneighbour
@world[row][col-1].hasneighbour
end
end
end
}
}
# then go through all cells in the world and determine their
fate
@world.each {
|row|
row.each { |cell|
# for each cell determine its fate
cell.fate
}
}
end
See if this little script gives you some fresh ideas...
#!/usr/bin/ruby -w
world = [ ]
# generate random world
10.times do
world.push(Array.new(10) { rand(2) == 1 ? "X" : " " })
end
# and later...
world.each_with_index do |row, y|
row.each_with_index do |cell, x|
# list all possible neighbors
neighbors = [ ]
[-1, 0, 1].each { |n| neighbors.push( [x + n, y + -1],
[x + n, y + 0],
[x + n, y + 1] ) }
# filter neighbor list with bounds checking
neighbors.delete_if { |xy| xy.include?(-1) ||
xy[0] >= row.size ||
xy[1] >= world.size ||
(xy[0] == x && xy[1] == y) }
# process neighbor cells
puts "#{x}, #{y} is next to:"
neighbors.each do |e|
puts "\t#{e[0]}, #{e[1]}"
end
end
end
__END__
Hope that helps.
James Edward Gray II