Thursday, November 26, 2009

Conway's Game of Life - Glimmer Edition

I recently attended a Chicago Ruby group meeting where everybody paired up on implementing a version of Conway's Game of Life in Ruby. At the end of the meeting, the logic of the game was completely test-driven and ready for use, so I decided to slap on a Glimmer UI on top of it afterward:



Here is Glimmer's repository:
http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/

Here are the tests written with RSpec:
http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/spec/samples/game_of_life/

And, here is the implementation:
http://dev.eclipse.org/svnroot/technology/org.eclipse.glimmer.core/samples/game_of_life/

The game logic is in grid.rb and cell.rb whereas the UI code is in game_of_life.rb. cell_presenter.rb provides the presenter needed for data-binding with the MVP pattern.

Here is how the Glimmer UI code looks like:

width = 7
height = 7
grid = Grid.new(width, height)
shell {
  text "Conway's Game of Life (Glimmer Edition)"
  composite {
    layout GridLayout.new(width,true)
    (0...width).each { |x|
      (0...height).each { |y|
        button {
          layout_data GridData.new(fill, fill, true, true)
          text bind(CellPresenter.new(grid, x, y), :alive)
          on_widget_selected {
            grid.toggle_aliveness!(x, y)
          }
        }
      }
    }
    button {
      text "Step"
      on_widget_selected {
        grid.step!
      }
    }
  }
}.open

It simply iterates over the Game of Life grid cells, wrapping each with a presenter and binding it to a button in the UI:
text bind(CellPresenter.new(grid, x, y), :alive)

When a button is clicked, the cell aliveness is toggled to "alive" (showing 'o') or "dead". This enables player to lay out the grid of cells:
on_widget_selected {
  grid.toggle_aliveness!(x, y)
}

Finally, to step the game, there is a "Step" button that steps the grid into the next generation, resulting in cells that die, new cells born, and cells that simply continue to be alive:
button {
  text "Step"
  on_widget_selected {
    grid.step!
  }
}

One thing that is noteworthy is that Glimmer's support for data-binding greatly facilitated the decoupling of the UI from the domain logic enabling us to write our domain code in full isolation of the UI, and later adding the UI and its related presentation logic via the Glimmer UI DSL and the presenter.

Hit me up with comments or an email if you have any questions.

Happy thanksgiving!

1 comment:

Dave Orme said...

Schweet!