#12 Conway's Game of Life ver.2 (flash on 2009-8-28)

by krogue
Conway's Game of Life
*
* 1px=1セル、463x463のライフゲーム。
* クリック: 拡大機能の開始/終了
* キー押下: 初期化(タイムラグ有)
*
* @author krogue
♥0 | Line 180 | Modified 2009-08-28 21:37:24 | MIT License
play

ActionScript3 source code

/**
 * Copyright krogue ( http://wonderfl.net/user/krogue )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/pBin
 */

/**
 * Conway's Game of Life
 *
 * 1px=1セル、463x463のライフゲーム。
 * クリック: 拡大機能の開始/終了
 * キー押下: 初期化(タイムラグ有)
 *
 * @author krogue
 */
package  {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    
    [SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="60")]
    public class ConwayGame extends Sprite {
        private var game:Game;
        private var updateCount:uint; // 0..59 の範囲でループ
        
        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 {
            updateCount = 0;
            game = addChild(new Game()) as Game;
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
            stage.addEventListener(MouseEvent.CLICK, clickHandler);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
        }
        
        private function update():void {
            if (updateCount == 0) {
                game.draw();
            }
            game.drawZoomWindow();
            updateCount++;
            if (updateCount >= 60) {
                updateCount = 0;
            }
        }
        
        private function keyUpHandler(event:KeyboardEvent):void {
            game.reset();
        }
        
        private function clickHandler(event:MouseEvent):void {
            game.focus(event.stageX, event.stageY);
            game.zoom = !game.zoom;
        }
        
        private function mouseMoveHandler(event:MouseEvent):void {
            game.focus(event.stageX, event.stageY);
        }
    }
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getTimer;

class Game extends Sprite {
    private const WIDTH:int = 465;
    private const HEIGHT:int = 465;
    private const ZOOM_WIDTH:int = WIDTH / 15; // = 31
    private const ZOOM_HEIGHT:int = HEIGHT / 15; // = 31
    private const SCALE:int = 5;
    private const COLOR_LIFE:uint = 0xFF000000;
    private const COLOR_DEAD:uint = 0xFFFFFFFF;
    private const INIT_LIFE_NUM:int = WIDTH * HEIGHT / 5;
    
    private var _zoom:Boolean = false;
    private var rows:Array /* of Array */ = new Array(HEIGHT);
    private var zoomRect:Rectangle =
        new Rectangle(0, 0, ZOOM_WIDTH, ZOOM_HEIGHT);
    
    private var bitmap:Bitmap = addChildAt(new Bitmap(), 0) as Bitmap;
    private var window:Bitmap = addChildAt(new Bitmap(), 1) as Bitmap;
    private var shape:Shape = addChildAt(new Shape(), 2) as Shape;
    
    public function Game() {
        bitmap.bitmapData = new BitmapData(WIDTH, HEIGHT, false, COLOR_DEAD);
        window.bitmapData = new BitmapData(zoomRect.width, zoomRect.height,
            false, COLOR_DEAD);
        window.scaleX = SCALE;
        window.scaleY = SCALE;
        reset();
    }
    
    private function updateCount():void {
        var endY:int = rows.length - 1;
        for (var y:int = 1; y < endY; y++) {
            var cols:Array /* of Cell */ = rows[y];
            var ncols:Array /* of Cell */ = rows[y + 1];
            var endX:int = cols.length - 1; 
            for (var x:int = 1; x < endX; x++) {
                var col:Cell = cols[x];
                if (col.life) {
                    cols[x + 1].count++;
                    ncols[x - 1].count++;
                    ncols[x].count++;
                    ncols[x + 1].count++;
                }
                if (cols[x + 1].life) col.count++;
                if (ncols[x - 1].life) col.count++;
                if (ncols[x].life) col.count++;
                if (ncols[x + 1].life) col.count++;
            }
        }
    }
    
    public function draw():void {
        updateCount();
        const bmd:BitmapData = bitmap.bitmapData;
        bmd.lock();
        var endY:int = rows.length - 1;
        for (var y:int = 1; y < endY; y++) {
            var cols:Array /* of Cell */ = rows[y];
            var endX:int = cols.length - 1;
            for (var x:int = 1; x < endX; x++) {
                var col:Cell = cols[x];
                col.life = ((col.count == 3) || (col.count == 2 && col.life));
                bmd.setPixel(x, y, (col.life ? COLOR_LIFE : COLOR_DEAD));
                col.count = 0;
            }
        }
        bmd.unlock();
    }
    
    public function drawZoomWindow():void {
        shape.visible = _zoom;
        window.visible = _zoom;
        if (_zoom) {
            shape.graphics.clear();
            shape.graphics.lineStyle(0, 0x00FF00);
            shape.graphics.drawRect(zoomRect.x, zoomRect.y,
                zoomRect.width, zoomRect.height);
            if (zoomRect.x < WIDTH / 2 - zoomRect.width / 2) {
                window.x = WIDTH - window.width;
            } else {
                window.x = 0;
            }
            window.bitmapData.copyPixels(bitmap.bitmapData, zoomRect,
                new Point());
        }
    }
    
    public function focus(x:int, y:int):void {
        const hw:int = zoomRect.width / 2;
        const hh:int = zoomRect.height / 2; 
        zoomRect.x = Math.min(Math.max(x, hw), WIDTH - hw) - hw;
        zoomRect.y = Math.min(Math.max(y, hh), HEIGHT - hh) - hh;
    }
    
    public function reset():void {
        for (var y:int = 0; y < rows.length; y++) {
            var cols:Array = new Array(WIDTH);
            for (var x:int = 0; x < cols.length; x++) {
                cols[x] = new Cell((y * WIDTH + x < INIT_LIFE_NUM), 0);
            }
            rows[y] = cols;
        }
        for (var i:int = HEIGHT * WIDTH - 1; i > 0; i--) {
            var index:int = Math.floor(Math.random() * (i + 1));
            var tx:int = index % WIDTH;
            var ty:int = index / WIDTH;
            var ix:int = i % WIDTH;
            var iy:int = i / WIDTH;
            var work:Cell = rows[ty][tx];
            rows[ty][tx] = rows[iy][ix];
            rows[iy][ix] = work;
        }
    }
    
    public function get zoom():Boolean {
        return _zoom;
    }
    
    public function set zoom(value:Boolean):void {
        _zoom = value;
    }
}

class Cell {
    public var life:Boolean;
    public var count:uint;
    
    public function Cell(life:Boolean, count:uint) {
        this.life = life;
        this.count = count;
    }
}