「グライダーを打ち出すグライダー・ガン」かっこよすぎ。
⇒ ライフゲーム - Wikipedia
出力したライフゲームの swf (LifeGame.swf)
メインクラスのソースコード (LifeGame.as)
package {
import flash.display.*;
import flash.events.*;
import flash.utils.*;
import info.nilab.*;
// The Game of Life (Conway's Game of Life)
public class LifeGame extends Sprite {
private const DEFAULT_CELL_WIDTH:int = 20;
private const DEFAULT_CELL_HEIGHT:int = 20;
private const DEFAULT_INTERVAL:int = 100;
private var cells:Cells;
private var shape:Shape;
private var cellWidth:int = DEFAULT_CELL_WIDTH;
private var cellHeight:int = DEFAULT_CELL_HEIGHT;
private var interval:int = DEFAULT_INTERVAL;
private var aCellPixelWidth:int;
private var aCellPixelHeight:int;
public function LifeGame() {
// QUERY_STRINGパラメータ取得
// LifeGame.swf?width=20&height=20&interval=100
// 再コンパイルしなくてもある程度のカスタマイズができるように
var param:Object = loaderInfo.parameters;
if(param["width"] != undefined){
try{
cellWidth = parseInt(param["width"]);
}catch(e:Error){
cellWidth = DEFAULT_CELL_WIDTH;
}
}
if(param["height"] != undefined){
try{
cellHeight = parseInt(param["height"]);
}catch(e:Error){
cellHeight = DEFAULT_CELL_HEIGHT;
}
}
if(param["interval"] != undefined){
try{
interval = parseInt(param["interval"]);
}catch(e:Error){
interval = DEFAULT_INTERVAL;
}
}
if(cellWidth < 0 || cellWidth > 100){
cellWidth = DEFAULT_CELL_WIDTH;
}
if(cellHeight < 0 || cellHeight > 100){
cellHeight = DEFAULT_CELL_HEIGHT;
}
if(interval < 50 || interval > 5000){
interval = DEFAULT_INTERVAL;
}
// 描画内容保持オブジェクト
shape = new Shape();
addChild(shape);
var timer:Timer = new Timer(interval, 0);
timer.addEventListener(TimerEvent.TIMER, next);
timer.start();
}
private function next(evt:TimerEvent):void {
if(cells == null){
// コンストラクタでは、まだロード途中ということで
// loaderInfo.width や loaderInfo.height が使えない
// サイズから自動的に1つのセルの幅と高さを決定する
aCellPixelWidth = loaderInfo.width / cellWidth;
aCellPixelHeight = loaderInfo.height / cellHeight;
// stage プロパティでも良いかも?
//aCellPixelWidth = stage.width / cellWidth;
//aCellPixelHeight = stage.height / cellHeight;
// 初回時のCells生成
cells = new Cells(cellWidth, cellHeight);
}else{
cells = cells.next();
}
drawCells(shape, cells, aCellPixelWidth, aCellPixelHeight);
}
private static function drawCells(s:Shape, cells:Cells, pw:int, ph:int):Shape {
s.graphics.clear();
for(var y:int=0; y<cells.height; y++){
for(var x:int=0; x<cells.width; x++){
if(cells.get(x, y)){
s.graphics.lineStyle(0, 0xff0000); // 線幅, 線色
s.graphics.beginFill(0xff0000);
s.graphics.drawRect(x * pw, y * ph, pw, ph);
s.graphics.endFill();
}else{
s.graphics.lineStyle(0, 0x000000); // 線幅, 線色
s.graphics.beginFill(0x000000);
s.graphics.drawRect(x * pw, y * ph, pw, ph);
s.graphics.endFill();
}
}
}
return s;
}
}
}
ライフゲームのアルゴリズムクラス info.nilab.Cells (Cells.as)
package info.nilab {
public class Cells {
private var cells:Array;
private var _width:int;
private var _height:int;
public function Cells(width:int=20, height:int=20, cells:Array=null) {
this._width = width;
this._height = height;
if(cells != null){
this.cells = cells;
}else{
this.cells = createCells(width, height);
}
}
public function get width():int {
return _width;
}
public function get height():int {
return _height;
}
public function get(x:int, y:int):Boolean {
return cells[key(x,y)];
}
public function next():Cells {
var a:Array = new Array();
for(var y:int=0; y<height; y++){
for(var x:int=0; x<width; x++){
a[key(x,y)] = nextGeneration(x, y);
}
}
return new Cells(width, height, a);
}
private function nextGeneration(x:int, y:int):Boolean {
var count:int = countNeighbors(x, y);
if(cells[key(x,y)]){
if(count == 2 || count == 3){
return true; // unchanged まだまだがんばるでふ
}else{
return false; // うへぇ overcrowding
}
}else{
if(count == 3){
return true; // 生まれろ新しい生命よ
}else{
return false;
}
}
}
private function countNeighbors(cx:int, cy:int):int {
var count:int = 0;
for(var y:int=cy-1; y<=cy+1; y++){
for(var x:int=cx-1; x<=cx+1; x++){
if(x!=cx || y!=cy){
// 上下左右ワープループ判定
var xx:int = x;
var yy:int = y;
if(cx == -1){
xx = _width - 1; // 最大値
}
//if(cx == _width){
if(cx == _width - 1){ // 2007-04-14バグ修正
xx = 0; // 最小値
}
if(cy == -1){
yy = _height - 1; // 最大値
}
//if(cy == _height){
if(cy == _height - 1){ // 2007-04-14バグ修正
yy = 0; // 最小値
}
if(cells[key(xx,yy)]){
count++;
}
}
}
}
return count;
}
private static function createCells(w:int, h:int):Array {
var a:Array = new Array();
for(var y:int=0; y<h; y++){
for(var x:int=0; x<w; x++){
a[key(x,y)] = getRandomBoolean();
}
}
return a;
}
// 連想配列を使ってみたかったので
private static function key(x:int, y:int):String {
return x + "," + y;
}
private static function getRandomBoolean():Boolean {
// 疑似乱数を取得(0 <= n < 1)
var n:Number = Math.random();
// 適当な値(0.3)より小さいときに true を返す
if(n < 0.3){
return true;
}else{
return false;
}
}
}
}
コンパイル
LifeGame.as と Cells.as を同じディレクトリに置いてコンパイルしようとしたら失敗した。
エラー: source-path で見つかったファイルのパッケージ構造 '' は、定義のパッケージ 'nilab' と同じである必要があります。
というメッセージが出た。
LifeGame.as と同じディレクトリに Cells.as を置いていたがダメらしい。
Java と同じく パッケージ構造と同じようにディレクトリ構造を作る必要がある。
C:\work\LifeGame.as
C:\work\info\nilab\Cells.as
こんな感じのファイル配置。
で、コンパイル。
C:\work>mxmlc -default-size 240 240 -default-frame-rate 30 -default-background-color 0xFFFFFF LifeGame.as
これで LifeGame.swf が生成される。
tags: zlashdot Flash Flash Flex
Posted by NI-Lab. (@nilab)