I am drawing a cellular automaton simulation on a Flex Canvas. I alternate computing the state of the automaton with updating the graphics on the Panel. However, the updating of the Panel does not seem to be "keeping up" with the update of the CA state.
I'm wondering whether I am doing something wrong with my handling of the graphics code. The code is below. Sorry it's so lengthy, but I don't think the problem will happen with anything simpler (well, it probably will, but I'm not certain I want to take the time to find it).
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init();">
<mx:Script>
<![CDATA[
private static const universeRadius:uint = 8;
private var universes:Array = new Array();
private var currentUniverse:uint = 0;
private var squareHeight:uint;
private var squareWidth:uint;
private function init():void {
squareHeight = myCanvas.height / universeRadius;
squareWidth = myCanvas.width / universeRadius;
initUniverses();
while (true) {
trace("Calling draw()");
draw();
trace("Calling updateUniverse()");
updateUniverse();
}
}
private function initUniverses():void {
var universe0:Array = new Array();
var universe1:Array = new Array();
var i:int;
for (i = 0; i < universeRadius; i++) {
var universe0Row:Array = new Array();
var universe1Row:Array = new Array();
var j:int;
for (j = 0; j < universeRadius; j++) {
if (Math.random() < 0.5) {
universe0Row[j] = 0;
} else {
universe0Row[j] = 1;
}
universe1Row[j] = 0;
}
universe0[i] = universe0Row;
universe1[i] = universe1Row;
}
universes[0] = universe0;
universes[1] = universe1;
}
private function normalize(pos:int):int {
return (pos + universeRadius) % universeRadius;
}
private function updateUniverse():void {
var newUniverse:int = 1 - currentUniverse;
var i:int;
for (i = 0; i < universeRadius; i++) {
var j:int;
for (j = 0; j < universeRadius; j++) {
var dx:int;
var dy:int;
var count:int = 0;
for (dx = -1; dx <= 1; dx++) {
var neighborX:int = normalize(i + dx);
for (dy = -1; dy <= 1; dy++) {
var neighborY:int = normalize(j + dy);
if ((dx != 0 || dy != 0) &&
universes[currentUniverse][neighborX][neighborY] == 1) {
count++;
}
}
}
var currentCell:int = universes[currentUniverse][i][j];
if (currentCell == 1) {
// 1. Any live cell with fewer than two live neighbours
// dies, as if caused by underpopulation.
if (count < 2) {
universes[newUniverse][i][j] = 0;
}
// 2. Any live cell with more than three live neighbours
// dies, as if by overcrowding.
else if (count > 3) {
universes[newUniverse][i][j] = 0;
}
// 3. Any live cell with two or three live neighbours
// lives on to the next generation.
else {
universes[newUniverse][i][j] = 1;
}
} else {
// 4. Any dead cell with exactly three live neighbours
// becomes a live cell.
if (count == 3) {
universes[newUniverse][i][j] = 1;
} else {
universes[newUniverse][i][j] = 0;
}
}
}
}
currentUniverse = newUniverse;
}
private function draw():void {
myCanvas.graphics.clear();
myCanvas.graphics.beginFill(0xFFFFFF, 1.0);
myCanvas.graphics.drawRect(0, 0, myCanvas.width, myCanvas.height);
var i:int;
for (i = 0; i < universeRadius; i++) {
var j:int;
for (j = 0; j < universeRadius; j++) {
if (universes[currentUniverse][i][j] == "1") {
myCanvas.graphics.beginFill(0x000000, 1.0);
myCanvas.graphics.drawRect(
j * squareWidth, i * squareHeight, squareWidth, squareHeight)
}
}
}
myCanvas.graphics.endFill();
}
]]>
</mx:Script>
<mx:Panel title="Life" height="95%" width="95%"
paddingTop="5" paddingLeft="5" paddingRight="5" paddingBottom="5">
<mx:Canvas id="myCanvas" borderStyle="solid" height="100%" width="100%">
</mx:Canvas>
</mx:Panel>
</mx:Application>