「グライダーを打ち出すグライダー・ガン」かっこよすぎ。
ライフゲーム - 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)