Ruby Game of Life in WPF
Thursday, 8 July 2010
A new Ruby Challenge for Newbies has been issued over at RubyLearning by Elise Huard — whom I had the pleasure of hearing talk about evaluating the quality of Rails applications at the Scottish Ruby Conference earlier this year. This challenge, called The Game of Life involves implementing John Conway’s famous Game of Life automaton in Ruby. To explain what it is, let’s quote the Wikipedia article:
The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, live or dead. Every cell interacts with its eight neighbours, which are the cells that are directly horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:
- Any live cell with fewer than two live neighbours dies, as if caused by under-population.
- Any live cell with more than three live neighbours dies, as if by overcrowding.
- Any live cell with two or three live neighbours lives on to the next generation.
- Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
The initial pattern constitutes the seed of the system. The first generation is created by applying the above rules simultaneously to every cell in the seed—births and deaths happen simultaneously, and the discrete moment at which this happens is sometimes called a tick (in other words, each generation is a pure function of the one before). The rules continue to be applied repeatedly to create further generations.
So, of course, I started typing. It is up to the entrant to decide whether they are going to produce a torus-model (where ‘neighbour’ cells for those on the edge of the board wrap around to the other side of the board) or a box-model (whereby edge cells have no neighbours on those sides). I opted for the former. As I was working on this during a lunchbreak at work, I had no access to a UNIX-based machine on which to run the ncurses simulation packaged with the challenge. So, like any programmer worth his salt, I decided to (after spending an hour or two creating an actual working solution, and unit testing the hell out of it) create a visualisation using WPF — written in IronRuby, so it’s still compliant with the challenge!
All my code for this is available at my fork of the challenge on GitHub, but here’s the important part; the WPF code. Isn’t IronRuby awesome?
require 'WindowsBase'
require 'PresentationFramework'
require 'PresentationCore'
require 'System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
class GameOfLifeSimulation
include System::Windows::Controls
include System::Windows::Media
include System::Windows::Shapes
def initialize(game, width = 100, height = 100)
@window = System::Windows::Window.new
@window.background = Brushes.Black
@window.width = width
@window.height = height
@window.resize_mode = System::Windows::ResizeMode.NoResize
@window.title = "WPF Game of Life!"
game.simulation = self
update(game)
app = System::Windows::Application.new
app.run(@window)
end
def update(game)
@grid = Grid.new
@grid.mouse_down { game.evolve }
game.size.times do
@grid.column_definitions.add ColumnDefinition.new
@grid.row_definitions.add RowDefinition.new
end
game.state.each_index do |row_index|
row = game.state[row_index]
row.each_index do |col_index|
col = row[col_index]
rect = Rectangle.new
rect.fill = col.alive? ? Brushes.YellowGreen : Brushes.DarkGreen
rect.stroke = Brushes.Black
Grid.set_row(rect, row_index)
Grid.set_column(rect, col_index)
@grid.children.add(rect)
end
end
@window.content = @grid
end
end
As long as your implementation of the Game of Life follows the rules of the challenge and implements the observer pattern with an update() callback in order to use this simulation (see my solution for an example), this should enable you to visualise your Game of Life challenge solution on Windows.
I do not, by the way, plan on officially submitting this entry to this competition purely because I do not consider myself a Ruby-newbie — although I fully expect lots of other entries from people who have been doing this half as long as I have to produce far superior solutions.