#11 forked from: #10 forked from: #9 Conway's Game of Life(flash on 2009-8-23)
forked from #10 forked from: #9 Conway's Game of Life(flash on 2009-8-23) (diff: 150)
Conway's Game of Life * * 1px=1セル、465x465のライフゲーム。 * クリック: クリックした場所の拡大 or 拡大機能の停止 * キー押下: 初期化 * * NOTE: 前回はセルが少なかったので今回は1px=1セルで。小さすぎるよ…… * NOTE: テンプレート作成&試用 * NOTE: 標準コーディングルールに一部準拠(インデントなど) * NOTE: Pointの自作をやめた * NOTE: ズーム機能を追加 * NOTE: フレームレートを下げた * NOTE: 初期化(リセットボタン) * NOTE: 80桁で折り返しは難しい([SWF()]の時点で80+) * @author krogue
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/hNg8
*/
/**
* Conway's Game of Life
*
* 1px=1セル、465x465のライフゲーム。
* クリック: クリックした場所の拡大 or 拡大機能の停止
* キー押下: 初期化
*
* NOTE: 前回はセルが少なかったので今回は1px=1セルで。小さすぎるよ……
* NOTE: テンプレート作成&試用
* NOTE: 標準コーディングルールに一部準拠(インデントなど)
* NOTE: Pointの自作をやめた
* NOTE: ズーム機能を追加
* NOTE: フレームレートを下げた
* NOTE: 初期化(リセットボタン)
* NOTE: 80桁で折り返しは難しい([SWF()]の時点で80+)
* @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.events.KeyboardEvent;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.geom.ColorTransform;
[SWF(width="465", height="465", backgroundColor="0xCCCCCC", frameRate="15")]
public class ConwayGame extends Sprite {
private const WIDTH:int = 465;
private const HEIGHT:int = 465;
private const ZOOM_WIDTH:int = WIDTH / 9; // ZOOM対象の幅(拡大前)
private const ZOOM_HEIGHT:int = HEIGHT / 9; // ZOOM対象の高さ(拡大前)
private const INIT_LIFE_NUM:int = WIDTH * HEIGHT / 5;
private const COLOR_LIFE:uint = 0xFFFFFF;
private const COLOR_DEATH:uint = 0x000000;
private var bitmap:Bitmap;
private var fgBitmapData:BitmapData;
private var bgBitmapData:BitmapData;
private var window:Bitmap;
private var windowBitmapData:BitmapData;
private var zoom:Shape;
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 bitmap
points = new Array(WIDTH * HEIGHT); /* of Point */
initBitmapData();
bitmap = new Bitmap(fgBitmapData, PixelSnapping.NEVER, false);
// init window
zoom = new Shape();
zoom.visible = false;
zoom.graphics.lineStyle(1, 0x00FF00);
zoom.graphics.drawRect(0, 0, ZOOM_WIDTH, ZOOM_HEIGHT);
windowBitmapData = new BitmapData(zoom.width, zoom.height, false,
COLOR_DEATH);
window = new Bitmap(windowBitmapData, PixelSnapping.NEVER, false);
window.scaleX = 3;
window.scaleY = 3;
window.visible = false;
// add child
addChild(bitmap);
addChild(zoom);
addChild(window);
// add event listener
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.addEventListener(MouseEvent.CLICK, clickHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
}
private function initBitmapData():void {
// init points
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);
}
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);
const COLOR_DEATH:uint = COLOR_DEATH;
const rectangle:Rectangle = new Rectangle(1, 1,
fg.width - 1, fg.height - 1);
for (var y:int = 0, h:int = fg.height; y < h; y++) {
for (var x:int = 0, w:int = fg.width; x < w; x++) {
var pixel:uint;
var lifeCount:int = 0; // 周囲の生存数
if (rectangle.contains(x, y)) {
pixel = fg.getPixel(x - 1, y - 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
pixel = fg.getPixel(x + 0, y - 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
pixel = fg.getPixel(x + 1, y - 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
pixel = fg.getPixel(x - 1, y + 0);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
pixel = fg.getPixel(x + 1, y + 0);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
pixel = fg.getPixel(x - 1, y + 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
pixel = fg.getPixel(x + 0, y + 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
pixel = fg.getPixel(x + 1, y + 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
} else {
if (y - 1 >= 0) {
if (x - 1 >= 0) {
pixel = fg.getPixel(x - 1, y - 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
}
pixel = fg.getPixel(x + 0, y - 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
if (x + 1 < w) {
pixel = fg.getPixel(x + 1, y - 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
}
}
if (x - 1 >= 0) {
pixel = fg.getPixel(x - 1, y + 0);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
}
if (x + 1 < w) {
pixel = fg.getPixel(x + 1, y + 0);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
}
if (y + 1 < h) {
if (x - 1 >= 0) {
pixel = fg.getPixel(x - 1, y + 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
}
pixel = fg.getPixel(x + 0, y + 1);
lifeCount += (pixel != COLOR_DEATH ? 1 : 0);
if (x + 1 < w) {
pixel = fg.getPixel(x + 1, y + 1);
lifeCount += (pixel != 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 {
windowBitmapData.lock();
windowBitmapData.copyPixels(bitmap.bitmapData,
new Rectangle(zoom.x, zoom.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 mouseMoveHandler(event:MouseEvent):void {
// update window x/y
if (event.stageX < WIDTH / 2) {
window.x = WIDTH - window.width;
} else {
window.x = 0;
}
window.y = HEIGHT - window.height;
// update zoom
zoom.x = range(event.stageX - zoom.width / 2,
0, WIDTH - zoom.width);
zoom.y = range(event.stageY - zoom.height / 2,
0, HEIGHT - zoom.height);
}
// min <= n <= max に収まるように値を修正する
private function range(n:Number, min:Number, max:Number):Number {
return Math.min(Math.max(n, min), max);
}
private function clickHandler(event:MouseEvent):void {
if (window.visible) {
zoom.visible = false;
window.visible = false;
} else {
updateWindow();
zoom.visible = true;
window.visible = true;
}
}
private function keyUpHandler(event:KeyboardEvent):void {
initBitmapData();
bitmap.bitmapData = fgBitmapData;
}
}
}
