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

#10 forked from: #9 Conway's Game of Life(flash on 2009-8-23)

Conway's Game of Life
*
* 1px=1セル、465x465のライフゲーム。クリックした箇所を反転拡大します。
* 標準の拡大機能の方が便利です。
*
* NOTE: 前回はセルが少なかったので今回は1px=1セルで。小さすぎるよ……
* NOTE: テンプレート作成&試用
* NOTE: 標準コーディングルールに一部準拠(インデントなど)
* NOTE: Pointの自作をやめた
* NOTE: ズーム機能を追加
* TODO: 初期化(リセットボタン)
* @author krogue
Get Adobe Flash player
by krogue 24 Aug 2009
/**
 * Copyright krogue ( http://wonderfl.net/user/krogue )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/d7Kx
 */

/**
 * Conway's Game of Life
 *
 * 1px=1セル、465x465のライフゲーム。クリックした箇所を反転拡大します。
 * 標準の拡大機能の方が便利です。
 *
 * NOTE: 前回はセルが少なかったので今回は1px=1セルで。小さすぎるよ……
 * NOTE: テンプレート作成&試用
 * NOTE: 標準コーディングルールに一部準拠(インデントなど)
 * NOTE: Pointの自作をやめた
 * NOTE: ズーム機能を追加
 * TODO: 初期化(リセットボタン)
 * @author krogue
 */
package  {
    import flash.display.Sprite;
    import flash.display.Shape;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.PixelSnapping;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Rectangle;
    import flash.geom.Point;
    import flash.geom.ColorTransform;
    
    [SWF(width="465", height="465", backgroundColor="0xCCCCCC", frameRate="60")]
    public class ConwayGame extends Sprite {
        private const WIDTH:int = 465;
        private const HEIGHT:int = 465;
        private const ZOOM_WIDTH:int = WIDTH / 8; // ZOOM対象の幅(拡大前)
        private const ZOOM_HEIGHT:int = HEIGHT / 8; // ZOOM対象の高さ(拡大前)
        private const INIT_LIFE_NUM:int = WIDTH * HEIGHT / 5;
        private const COLOR_LIFE:uint = 0xFFFFFF;
        private const COLOR_DEATH:uint = 0x000000; // == 0 でないと動作しない
        private var bitmap:Bitmap;
        private var fgBitmapData:BitmapData;
        private var bgBitmapData:BitmapData;
        private var window:Bitmap;
        private var windowBitmapData:BitmapData;
        private var zoomPoint:Point;
        private var points:Array; /* of Point */
        
        public function ConwayGame() {
            addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
        }
        
        private function addedToStageHandler(event:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
            initialize();
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        
        private function enterFrameHandler(event:Event):void {
            update();
        }
        
        private function initialize():void {
            // init points
            points = new Array(WIDTH * HEIGHT); /* of Point */
            for (var y:int = 0; y < HEIGHT; y++) {
                for (var x:int = 0; x < WIDTH; x++) {
                    points[y * HEIGHT + x] = new Point(x, y);
                }
            }
            
            // randomize points
            for (var i:int = points.length - 1; i > 0; i--) {
                var index:int = Math.floor(Math.random() * (i + 1));
                var work:Point = points[index];
                points[index] = points[i];
                points[i] = work;
            }
            
            // init bitmap
            fgBitmapData = new BitmapData(WIDTH, HEIGHT, false, COLOR_DEATH);
            bgBitmapData = fgBitmapData.clone();
            points.every(function(point:*, index:int, array:Array /* of Point */):Boolean {
                if (index >= INIT_LIFE_NUM) {
                    // do nothing
                    return false; // break
                }
                fgBitmapData.setPixel(point.x, point.y, COLOR_LIFE);
                return true; // continue
            }, this);
            bitmap = addChild(new Bitmap(fgBitmapData, PixelSnapping.NEVER, false)) as Bitmap;
            
            // init window
            windowBitmapData = new BitmapData(ZOOM_WIDTH, ZOOM_HEIGHT, false, COLOR_DEATH);
            window = addChild(new Bitmap(windowBitmapData, PixelSnapping.NEVER, false)) as Bitmap;
            window.scaleX = 4;
            window.scaleY = 4;
            window.visible = false;
            
            // add event listener
            stage.addEventListener(MouseEvent.CLICK, clickHandler);
        }
        
        private function update():void {
            const fg:BitmapData = fgBitmapData;
            const bg:BitmapData = bgBitmapData;
            fg.lock();
            bg.lock();
            
            bg.fillRect(new Rectangle(0, 0, bg.width, bg.height), COLOR_DEATH);
            for (var y:int = 0; y < fg.height; y++) {
                for (var x:int = 0; x < fg.width; x++) {
                    var lifeCount:int = 0;
                    lifeCount += (fg.getPixel(x - 1, y - 1) != COLOR_DEATH ? 1 : 0);
                    lifeCount += (fg.getPixel(x + 0, y - 1) != COLOR_DEATH ? 1 : 0);
                    lifeCount += (fg.getPixel(x + 1, y - 1) != COLOR_DEATH ? 1 : 0);
                    lifeCount += (fg.getPixel(x - 1, y + 0) != COLOR_DEATH ? 1 : 0);
                    lifeCount += (fg.getPixel(x + 1, y + 0) != COLOR_DEATH ? 1 : 0);
                    lifeCount += (fg.getPixel(x - 1, y + 1) != COLOR_DEATH ? 1 : 0);
                    lifeCount += (fg.getPixel(x + 0, y + 1) != COLOR_DEATH ? 1 : 0);
                    lifeCount += (fg.getPixel(x + 1, y + 1) != COLOR_DEATH ? 1 : 0);
                    if ((lifeCount == 3) ||
                            (lifeCount == 2 && fg.getPixel(x, y) != 0)) {
                        bg.setPixel(x, y, COLOR_LIFE);
                    }
                }
            }
            
            bitmap.bitmapData = bg;
            fgBitmapData = bg;
            bgBitmapData = fg;
            
            fg.unlock();
            bg.unlock();
            
            if (window.visible) {
                updateWindow();
            }
        }
        
        private function updateWindow():void {
            const x:Number = range(zoomPoint.x - ZOOM_WIDTH / 2,
                    0, WIDTH - ZOOM_WIDTH);
            const y:Number = range(zoomPoint.y - ZOOM_HEIGHT / 2,
                   0, HEIGHT - ZOOM_HEIGHT);
            windowBitmapData.lock();
            windowBitmapData.copyPixels(bitmap.bitmapData,
                    new Rectangle(x, y, ZOOM_WIDTH, ZOOM_HEIGHT),
                    new Point(0, 0));
            windowBitmapData.colorTransform(
                    new Rectangle(0, 0, ZOOM_WIDTH, ZOOM_HEIGHT),
                    new ColorTransform(-1, -1, -1, 1, 255, 255, 255, 0));
            windowBitmapData.unlock();
        }
        
        private function clickHandler(event:MouseEvent):void {
            if (window.visible &&
                    window.hitTestPoint(event.stageX, event.stageY)) {
                window.visible = false;
                return;
            }
            zoomPoint = new Point(event.stageX, event.stageY);
            window.x = range(event.stageX - window.width / 2,
                    0, WIDTH - window.width);
            window.y = range(event.stageY - window.height / 2,
                    0, HEIGHT - window.height);
            updateWindow();
            window.visible = true;
        }
        
        // min <= n <= max に収まるように値を修正する
        private function range(n:Number, min:Number, max:Number):Number {
            return Math.min(Math.max(n, min), max);
        }
    }
}