In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Cellular Automaton

CellularAutomaton.as
by nox, 2010.7.9
http://handasse.blogspot.com/
1-9   : ルール設定 - セルの周りの生存セル数(0-8)に対応
: '.' 死亡, '&' 変化, '+' 誕生, '=' 維持
SPACE : 一時停止
ENTER : リセット
V     : メッセージ表示/非表示
Z     : 初期生存セルの割合を減少
X     : 初期生存セルの割合を増加
Get Adobe Flash player
by nox 13 Jul 2010
    Embed
/**
 * Copyright nox ( http://wonderfl.net/user/nox )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/6yen
 */

// CellularAutomaton.as
//  by nox, 2010.7.9
//  http://handasse.blogspot.com/

/*
1-9   : ルール設定 - セルの周りの生存セル数(0-8)に対応
      : '.' 死亡, '&' 変化, '+' 誕生, '=' 維持
SPACE : 一時停止
ENTER : リセット
V     : メッセージ表示/非表示
Z     : 初期生存セルの割合を減少
X     : 初期生存セルの割合を増加
*/

package {
    import flash.display.*;
    import flash.events.*;
    import flash.text.*;
    import flash.utils.*;
    import flash.geom.Point;

    [SWF (width="465", height="465", backgroundColor="0x000000", frameRate="60")]

    public class CellularAutomaton extends Sprite
    {
        private const R:int = 465, C:int = 465, C5:int = ((C-1) >> 5) + 1;
        private const RCinv:Number = 1.0 / (R * C);
        private const remainBits:int = ((~C + 1) & 0x1f) * R;
        // '.': death, '&': change, '+': birth, '=': survival
        private const ruleChar:Array = ['.', '&', '+', '=']
        private const log4inv:Number = 1.0 / Math.log(4.0);
        private const updateTime:uint = 500;

        private var bmpData:BitmapData = new BitmapData(R, C);
        private var cells:Array = new Array(R);
        private var modR:Array = new Array(R * 3);
        private var modC:Array = new Array(C * 3);
        // 0: death, 1: change, 2: birth, 3: survival
        private var rules:Array = [0, 0, 3, 2, 0, 0, 0, 0, 0];  // Conway's Game of Life
        private var rate:Number = 0.3;
        private var initRate:Number = rate;
        private var cnt:Array = new Array(R);
        private var ruleBits:Array = new Array(4);
        private var entropy:Number = 1.0;
        private var patterns:Array = [0, 0, 0, 0];
        private var txtData:TextField = new TextField();
        private var txtRules:TextField = new TextField();
        private var fps:Number = 0.0;
        private var drawCount:uint = 0;
        private var prevTimer:uint = 0;

        private function bitcount(bits:uint):uint {
            bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555);
            bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333);
            bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f);
            bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff);
            return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff);
        }

        private function init():void {
            var i:int, j:int;
            for (i = 0; i < R; i++) for (j = 0; j < C5; j++) cells[i][j] = 0;
            for (i = 0; i < R; i++) for (j = 0; j < C; j++)
                if (Math.random() < initRate) cells[i][j>>5] |= 1 << (j&0x1f);
        }

        private function next():void {
            var i:int, j:int, x:int, y:int;
            for (i = 0; i < R; i++) for (j = 0; j < C; j++) cnt[i][j] = 0;
            for (x = 0; x < R; x++) for (y = 0; y < C; y++)
                if (cells[x][y>>5] & 1 << (y&0x1f))
                    for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++)
                        if (i != 0 || j != 0) cnt[modR[x+i+R]][modC[y+j+C]]++;
            for (i = 0; i < 4; i++) patterns[i] = 0;
            for (x = 0; x < R; x++) {
                for (i = 0; i < 4; i++) for (j = 0; j < C5; j++) ruleBits[i][j] = 0;
                for (y = 0; y < C; y++)
                    ruleBits[rules[cnt[x][y]]][y>>5] |= 1 << (y&0x1f);
                for (i = 0; i < C5; i++) {
                    var cellBits:uint = cells[x][i];
                    cells[x][i] = cells[x][i] & ~ruleBits[0][i] ^ ruleBits[1][i] | ruleBits[2][i];
                    patterns[0] += bitcount(~cellBits & ~cells[x][i]);
                    patterns[1] += bitcount(cellBits & ~cells[x][i]);
                    patterns[2] += bitcount(~cellBits & cells[x][i]);
                    patterns[3] += bitcount(cellBits & cells[x][i]);
                }
            }
            patterns[0] -= remainBits;
            entropy = 0.0;
            for (i = 0; i < 4; i++) {
                if (patterns[i] == 0) continue;
                var p:Number = patterns[i] * RCinv;
                entropy -= p * Math.log(p) * log4inv;
            }
        }

        private function countAlive():int {
            var cnt:int = 0;
            for (var x:int = 0; x < R; x++)
                for (var c:int = 0; c < C5; c++)
                    cnt += bitcount(cells[x][c]);
            return cnt;
        }

        private function showData(cntAlive:uint):void {
            drawCount += 1;
            if (getTimer() - prevTimer >= updateTime) {
                fps = (drawCount * 1000 / (getTimer() - prevTimer) * 10 >> 0) / 10;
                prevTimer = getTimer();
                drawCount = 0;
            }
            txtData.htmlText = "<span class='c'>FPS = " + fps + " / " + stage.frameRate
                             + "\nN = " + cntAlive
                             + "\nH = " + (entropy * 100000 >> 0) / 100000 + "</span>";
        }

        private function showRules():void {
            var rule:String = "";
            for (var i:int = 0; i < 9; i++) rule += ruleChar[rules[i]];
            txtRules.htmlText = "<span class='c'>" + "[" + rule + "] "
                              + initRate + " / " + (rate * 100000 >> 0) / 100000 + "</span>";
        }

        private function onEnterFrame(event:Event):void {
            var cntAlive:uint = countAlive();
            showData(cntAlive);
            showRules();
            rate = cntAlive * RCinv;
            var color:uint = (rate * 0xff) << 16 | ((1.0 - rate) * 0xff) >> 0;
            var bgcolor:uint = (entropy * 0xff) << 8;
            bmpData.lock();
            for (var i:int = 0; i < R; i++) {
                for (var j:int = 0; j < C; j++) {
                    var bit:uint = cells[i][j>>5] >> (j&0x1f) & 1;
                    bmpData.setPixel(i, j, bit * color + (bit ^ 1) * bgcolor);
                }
            }
            bmpData.unlock();
            next();
        }

        private function onKeyDown(event:KeyboardEvent):void{
            if (49 <= event.keyCode && event.keyCode <= 57) {
                // '1'-'9' keys : set rules for number of neighbors (0-8)
                var idx:uint = event.keyCode - 49;
                rules[idx] = (rules[idx] + 1) & 0x3;
            } else {
                switch (event.keyCode) {
                case 32:  // Space : pause
                    if (stage.hasEventListener(Event.ENTER_FRAME))
                        stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
                    else
                        stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
                    break;
                case 86:  // 'V' : show / hide messages
                    if (stage.contains(txtData)) stage.removeChild(txtData);
                    else stage.addChild(txtData);
                    if (stage.contains(txtRules)) stage.removeChild(txtRules);
                    else stage.addChild(txtRules);
                    break;
                case 88:  // 'X' : decrease initial rate of population
                    initRate = (initRate * 10) >> 0;
                    initRate = initRate + 1;
                    initRate = (initRate > 10) ? 0.0 : initRate / 10;
                    break;
                case 90:  // 'Z' : increase initial rate of population
                    initRate = (initRate * 10) >> 0;
                    initRate = initRate - 1;
                    initRate = (initRate < 0) ? 1.0 : initRate / 10;
                    break;
                case 13:  // Enter : reset
                    init();
                    break;
                }
            }
            showRules();
        };

        public function CellularAutomaton() {
            stage.addChild(new Bitmap(bmpData));
            stage.addChild(txtData);
            stage.addChild(txtRules);
            stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);

            var i:int;
            for (i = 0; i < R * 3; i++) modR[i] = i % R;
            for (i = 0; i < C * 3; i++) modC[i] = i % C;
            for (i = 0; i < R; i++) {
                cells[i] = new Array(C5);
                cnt[i] = new Array(C);
            }
            for (i = 0; i < 4; i++) ruleBits[i] = new Array(C5);

            var styleSheet:StyleSheet = new StyleSheet();
            styleSheet.setStyle(".c", {fontFamily:"_typewriter", fontSize:"16px", color:"#ffffff"});
            txtData.styleSheet = txtRules.styleSheet = styleSheet;
            txtData.autoSize = txtRules.autoSize = TextFieldAutoSize.LEFT;
            txtData.y = 0;
            txtRules.y = stage.height - 24;
            prevTimer = getTimer();

            init();
        }
    }
}