Sunday 9 October 2011

Conway's Game of Life in haXe [NME & MassiveUnit]



The second day of try{harder} was dedicated to a single topic; test driven development (TDD).

The group was split into pairs and given the task of using TDD to write a solver for the game of life in AS3. After an hour we then threw away everything we had done, swapped partners and repeated the process.

This was extremely valuable for me as I had never written a unit test before. Seeing how different people tackled the same problem was fascinating and informative.

After repeating the process three times Stray asked if I was interested in teaming up with another attendee of the conference Alec McEachran to investigate unit testing in haXe. It was a great idea as it meant we both could investigate how unit testing worked in haXe and it would give me another code example for my talk the following day.

After a brief search we decided on Mike Stead's MassiveUnit for testing as the testing syntax looked similar to FlexUnit and it contained a toolchain for running the tests on multiple platforms.

An example of a test we wrote is:

[codesyntax lang="actionscript3" lines="normal"]
package ;
import massive.munit.Assert;
import Grid;

/**
* ...
* @author MikeC & Alec McEachran
*/

class GridTest
{
public var grid : Grid;

@Before
public function before():Void
{
grid = new Grid(3, 3);
}

@After
public function after():Void
{
grid = null;
}

@Test
public function initiallyThereAreNoLiveNeighbors():Void
{
var liveNeighbors = grid.getLiveNeighbors(1, 1);
Assert.isTrue(liveNeighbors == 0);
}

@Test
public function liveNeighborCountIsAccurate():Void
{
grid.set(0, 0, true);
grid.set(1, 0, true);
grid.set(2, 1, true);

var liveNeighbors = grid.getLiveNeighbors(1, 1);
Assert.isTrue(liveNeighbors == 3);
}

}

[/codesyntax]

It should look fairly familiar to anyone who has used FlexUnit before. The metatags @Before @After and @Test perform in exactly the same way as they do in FlexUnit. Another benefit of using munit over the built in testing framework in haXe is that you are given a tool to run tests on all platforms simultaneously:

[codesyntax lang="text"]
 haxelib run munit test test.hxml

[/codesyntax]

When executed you get something that looks like the following:



Which presents a nice graphical representation of the tests run and which failed (if any).

Once built and tested we decided to give the code a simple visual representation. We wanted to show off the ability for haXe to target multiple platforms. To do this we decided to go with NME which I had been experimenting around with recently.

NME is a library and tool chain for haXe designed to allow the developer to use the flash API on multiple platforms. They achieve this by writing platform targeted version of the flash API. So what this means is code such as the following:

[codesyntax lang="actionscript3" lines="no"]
package ;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.MovieClip;
import flash.geom.Rectangle;

/**
* ...
* @author MikeC & Alec McEachran
*/

class Render
{

private var _cellSize : Int;
private var _renderTarget : BitmapData;
private var _rect:Rectangle;

public function new(container:MovieClip, cols:Int, rows:Int, cellSize:Int)
{
_cellSize = cellSize;
_renderTarget = new BitmapData(cols * cellSize, rows * cellSize, false);
container.addChild(new Bitmap(_renderTarget));

_rect = new Rectangle(0, 0, _cellSize, _cellSize);
}

public inline function lock():Void
{
_renderTarget.lock();
_renderTarget.fillRect(_renderTarget.rect, 0xff0000);
}

public inline function renderCell(x:Int, y:Int, isLive:Bool):Void
{
if (isLive)
{
_rect.x = x * _cellSize;
_rect.y = y * _cellSize;
_renderTarget.fillRect(_rect, 0);
}
}

public inline function unlock():Void
{
_renderTarget.unlock();
}

}

[/codesyntax]

Will compile down to flash, c++ and Javascript! NME also includes packaging abilities for webos, android and ios. So with a few scripted command lines you can target most app marketplaces:

[codesyntax lang="text"]
haxelib run nme test YourProject.nmml flash
haxelib run nme update YourProject.nmml ios
haxelib run nme test YourProject.nmml webos
haxelib run nme test YourProject.nmml android
haxelib run nme test YourProject.nmml cpp
haxelib run nme test YourProject.nmml cpp -64

[/codesyntax]

What it means for this project is we could very quickly get a view for our game of life running in flash, JS and native desktop.

To show just how easy it is I made the following video:



You can see the HTML5 build here: http://mikecann.co.uk/projects/gameoflife/Export/html5/bin/

And the flash build here: http://mikecann.co.uk/projects/gameoflife/Export/flash/bin/MyApplication.swf

I have uploaded the source for the project here: http://mikecann.co.uk/projects/gameoflife/gameoflife.zip

4 comments:

  1. [...] one of the first times I’ve built in haXe, and it was both fun and informative. You can read Mike’s post about the project here, and browse the source-code on Github here. Filed under haxe, tdd [...]

    ReplyDelete
  2. [...] Conway’s Game of Life in haXe [NME & MassiveUnit] http://mikecann.co.uk/personal-project/conways-game-of-life-in-haxe-nme-massiveunit/ [...]

    ReplyDelete
  3. hi Michael! I love the haxe port of game of life! Thx! Btw, why your "MyApplication (MikeC-Win-PC's conflicted copy 2011-10-09)" run much faster than the version I built with nme? It feels like nme build has only 10 fps while your version has fps > 30. Thx!

    ReplyDelete
  4. Not sure ogg, I guess stuff has changed in NME since I did this sample. Perhaps the way I am doing things isnt the correct way now..

    ReplyDelete