From: James Edward Gray II Date: 2004-09-24T07:30:39+09:00 Subject: Re: Newbie: Case statement On Sep 23, 2004, at 4:09 PM, Graham Foster wrote: > 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