#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
/**
* 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);
}
}
}