Game of Life Color with Glider Gun
『ライフゲーム』のセルに色を付けたバージョンです。
色の意味は下記の通り。
オレンジ:誕生して次の世代も生き延びるセル
イエロー:2世代生きたセル
ブルー:3世代生きたセル
グリーン:4世代以上生き続けているセル
レッド:次の世代で死ぬことが決まっているセル
同時に【ゴスパーのグライダー銃】のデモも実装しました。
GLIDER GUN DEMO ボタンを押すと永久持続パターンである
GliderGunが始まります。
イギリスの数学者John Horton Conway博士が1970年に考案した
生命の誕生、進化、淘汰などのプロセスを簡易的なモデルで再現
したシミュレーションゲームである『ライフゲーム』を再現して
みました。
この『ライフゲーム』は単純に、セルに色が付いている時は「生」を、
色が付いていない時は「死」を表します。
生きているセルが死んだり、死んでいるセルから誕生するかは、
それぞれのセルの周囲にあるセル(合計8個)のセルによって
決まります。
ライフ進行(世代交代)によってセルが生きるか死ぬかの
法則(ルール?)は以下の通りです。
1. 現世代でセルが生きていて、周囲の生きているセルの数が1以下のとき
→ 次世代では過疎のため死にます。
2. 現世代でセルが生きていて、周囲の生きているセルの数が4以上のとき
→ 次世代では過密のため死にます。
3. 現世代でセルが生きていて、周囲の生きているセルの数が2または3のとき
→ 次世代でも生き残ります。
4. 現世代でセルが死んでいて、周囲の生きているセルの数が3のとき
→ 次世代で生が誕生します。
5. 現世代でセルが死んでいて、周囲の生きているセルの数が3でないとき
→ 次世代でも死んだままです。
この世代交代を繰り返す間に白黒のグリッドはいろんな模様に変化し
その中には有名なパターンもいくつかあるそうです。
と、書いておきながら実は僕もそこまで詳しくは知りませんので…
http://ja.wikipedia.org/wiki/ライフゲーム
でも参照してみて下さい。シンプルながら結構奥が深いです。
でもこれ、見た目シンプルなくせに重いし、
それよりなにより、きちんとロジック通りに動いているかが心配です。
/**
* Copyright mousepancyo ( http://wonderfl.net/user/mousepancyo )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/on6W
*/
/*
『ライフゲーム』のセルに色を付けたバージョンです。
色の意味は下記の通り。
オレンジ:誕生して次の世代も生き延びるセル
イエロー:2世代生きたセル
ブルー:3世代生きたセル
グリーン:4世代以上生き続けているセル
レッド:次の世代で死ぬことが決まっているセル
同時に【ゴスパーのグライダー銃】のデモも実装しました。
GLIDER GUN DEMO ボタンを押すと永久持続パターンである
GliderGunが始まります。
*/
/*
イギリスの数学者John Horton Conway博士が1970年に考案した
生命の誕生、進化、淘汰などのプロセスを簡易的なモデルで再現
したシミュレーションゲームである『ライフゲーム』を再現して
みました。
この『ライフゲーム』は単純に、セルに色が付いている時は「生」を、
色が付いていない時は「死」を表します。
生きているセルが死んだり、死んでいるセルから誕生するかは、
それぞれのセルの周囲にあるセル(合計8個)のセルによって
決まります。
ライフ進行(世代交代)によってセルが生きるか死ぬかの
法則(ルール?)は以下の通りです。
1. 現世代でセルが生きていて、周囲の生きているセルの数が1以下のとき
→ 次世代では過疎のため死にます。
2. 現世代でセルが生きていて、周囲の生きているセルの数が4以上のとき
→ 次世代では過密のため死にます。
3. 現世代でセルが生きていて、周囲の生きているセルの数が2または3のとき
→ 次世代でも生き残ります。
4. 現世代でセルが死んでいて、周囲の生きているセルの数が3のとき
→ 次世代で生が誕生します。
5. 現世代でセルが死んでいて、周囲の生きているセルの数が3でないとき
→ 次世代でも死んだままです。
この世代交代を繰り返す間に白黒のグリッドはいろんな模様に変化し
その中には有名なパターンもいくつかあるそうです。
と、書いておきながら実は僕もそこまで詳しくは知りませんので…
http://ja.wikipedia.org/wiki/ライフゲーム
でも参照してみて下さい。シンプルながら結構奥が深いです。
でもこれ、見た目シンプルなくせに重いし、
それよりなにより、きちんとロジック通りに動いているかが心配です。
*/
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
import com.bit101.components.*;
[SWF(width=465, height=465, backgroundColor=0xCFCFCF, frameRate=24)]
public class Main extends Sprite{
private var _w:int = stage.stageWidth;
private var _h:int = stage.stageHeight;
private var _rectList:Vector.<Rect> = new Vector.<Rect>();
private var _xNum:int = 45
private var _yNum:int = 40
private var _timer:Timer;
private var _interval:int;
private var _isGame:Boolean;
private var _startBtn:PushButton
private var _pauseBtn:PushButton
private var _griderGunBtn:PushButton
private var _label:Label
private var _radioBtn1:RadioButton;
private var _radioBtn2:RadioButton;
private var _radioBtn3:RadioButton;
private var _radioBtn4:RadioButton;
private var _griderGunList:Vector.<int> = Vector.<int>([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
public function Main() {
_startBtn = new PushButton(this, 180, 415, "LIFE GAME START", statLifeGame);
_griderGunBtn = new PushButton(this, 180, 440, "GLIDER GUN DEMO", statLifeGame);
makeGrid(_xNum, _yNum, 7, 8);
//
_interval = 150
}
private function makeGrid(xNum:int, yNum:int, xOffset:int, yOffset:int):void{
for(var i:int=0; i<yNum; i++){
for(var j:int=0; j<xNum; j++){
var grid:Rect = new Rect(true, false)
addChild(grid)
grid.x = grid.width * j + xOffset
grid.y = grid.height * i + yOffset
grid.id = j + i * xNum
grid.addEventListener(MouseEvent.MOUSE_OVER, rectVisibleChange)
grid.addEventListener(MouseEvent.CLICK, rectVisibleChange)
}
}
for(i=0; i<yNum; i++){
for(j=0; j<xNum; j++){
var rect:Rect = new Rect(false, true)
addChild(rect)
rect.x = rect.width * j + xOffset
rect.y = rect.height * i + yOffset
rect.id = j + i * xNum
rect.mouseEnabled = false
rect.visible = false
_rectList.push(rect)
}
}
}
private function rectVisibleChange(e:MouseEvent):void{
if(e.type == "click"){
if(_rectList[e.target.id].visible == false){
_rectList[e.target.id].visible = _rectList[e.target.id].nextLiveFlg = true
}else{
_rectList[e.target.id].visible = _rectList[e.target.id].nextLiveFlg = false
}
return
}
if(e.buttonDown == true){
if(_rectList[e.target.id].visible == false){
_rectList[e.target.id].visible = _rectList[e.target.id].nextLiveFlg = true
}else{
_rectList[e.target.id].visible = _rectList[e.target.id].nextLiveFlg = false
}
}
}
private function statLifeGame(e:MouseEvent):void{
if(e.currentTarget == _griderGunBtn){
if(_timer != null){
_timer.stop()
_timer.removeEventListener(TimerEvent.TIMER, update)
_timer = null
}
for(var i:int=0; i<_xNum * _yNum; i++){
_rectList[i].visible = _rectList[i].nextLiveFlg = false
if(_griderGunList[i] == 1){
_rectList[i].visible = _rectList[i].nextLiveFlg = true
}
}
}
_timer = new Timer(_interval)
_timer.addEventListener(TimerEvent.TIMER, update)
_timer.start()
//
_startBtn.removeEventListener(MouseEvent.CLICK, statLifeGame)
_startBtn.visible = false
//
if(_pauseBtn == null) _pauseBtn = new PushButton(this, 180, 415, "PAUSE", pauseLifeGame);
if(_label == null) _label = new Label(this, 350, 427, "Number of Life : 0");
if(_radioBtn1 == null) _radioBtn1 = new RadioButton(this, 10, 413, "Interval : 0.05 sec", false, radioBtnSelect);
if(_radioBtn2 == null) _radioBtn2 = new RadioButton(this, 10, 413+12, "Interval : 0.15 sec", true, radioBtnSelect);
if(_radioBtn3 == null) _radioBtn3 = new RadioButton(this, 10, 413+12+12, "Interval : 0.30 sec", false, radioBtnSelect);
if(_radioBtn4 == null) _radioBtn4 = new RadioButton(this, 10, 413+12+12+12, "Interval : 1.00 sec", false, radioBtnSelect);
}
private function pauseLifeGame(e:MouseEvent):void{
if(_pauseBtn.label == "PAUSE"){
_timer.stop()
_pauseBtn.label = "RESTART"
}else{
_timer.start()
_pauseBtn.label = "PAUSE"
}
}
private function radioBtnSelect(e:Event):void{
if(_timer){
_timer.stop()
_timer.removeEventListener(TimerEvent.TIMER, update)
_timer = null
}
switch(e.currentTarget){
case _radioBtn1:
_interval = 50
break;
case _radioBtn2:
_interval = 150
break;
case _radioBtn3:
_interval = 300
break;
case _radioBtn4:
_interval = 1000
break;
}
_timer = new Timer(_interval)
_timer.addEventListener(TimerEvent.TIMER, update)
if(_pauseBtn.label == "PAUSE") _timer.start()
}
private function update(e:TimerEvent):void{
var n:int
for(var i:int=0; i<_xNum * _yNum; i++){
_rectList[i].visible = _rectList[i].nextLiveFlg
if(_rectList[i].visible == true) n++
}
for(i=0; i<_xNum * _yNum; i++){
checkProp(_rectList[i])
_rectList[i].colorChange()
}
_label.text = "Number of Life : "+n
}
private function checkProp(rect:Rect):void{
var checkNum:int
//
if(rect.id > _xNum && rect.id % _xNum != 0) checkNum += singleCheck(_rectList[rect.id - _xNum - 1])
if(rect.id > _xNum) checkNum += singleCheck(_rectList[rect.id - _xNum])
if(rect.id > _xNum && rect.id % _xNum != _xNum-1) checkNum += singleCheck(_rectList[rect.id - _xNum + 1])
if(rect.id > 0) checkNum += singleCheck(_rectList[rect.id - 1])
if(rect.id < _xNum * _yNum-1) checkNum += singleCheck(_rectList[rect.id + 1])
if(rect.id < _xNum * (_yNum-1) && rect.id % _xNum != 0) checkNum += singleCheck(_rectList[rect.id + _xNum - 1])
if(rect.id < _xNum * (_yNum-1)) checkNum += singleCheck(_rectList[rect.id + _xNum])
if(rect.id < _xNum * (_yNum-1)-1 && rect.id % _xNum != _xNum-1) checkNum += singleCheck(_rectList[rect.id + _xNum + 1])
//
if(rect.visible == true){
if(checkNum <= 1 || checkNum >= 4){
rect.nextLiveFlg = false
}else{
rect.nextLiveFlg = true
}
}else{
if(checkNum == 3){
rect.nextLiveFlg = true
}else{
rect.nextLiveFlg = false
}
}
//
function singleCheck(r:Rect):int{
if(r.visible){
return 1
}else{
return 0
}
}
}
}
}
//
import flash.display.Sprite;
import flash.display.Shape;
import flash.filters.BlurFilter;
import flash.filters.BevelFilter;
class Rect extends Sprite{
private var _sh:Shape = new Shape()
private var _id:int
private var _lifeNum:int
private var _blur:BlurFilter
private var _bevel:BevelFilter
public var nextLiveFlg:Boolean
public function Rect(isLine:Boolean, isFill:Boolean){
if(isLine) _sh.graphics.lineStyle(0,0xC0C0C0)
if(isFill){
_blur = new BlurFilter(2, 2, 1)
_bevel = new BevelFilter(2, 90, 0xFFFFFF, 0.5, 0, 0.3, 4, 8)
_sh.filters = [_blur, _bevel]
_sh.graphics.beginFill(0xFF6600)
}else{
_sh.graphics.beginFill(0xFFFFFF)
}
_sh.graphics.drawRect(0, 0, 10, 10)
_sh.graphics.endFill()
addChild(_sh)
}
public function colorChange():void{
if(this.visible){
if(nextLiveFlg == true){
switch(_lifeNum){
case 0:
setColor(0xFF6600) //生まれたて(オレンジ)
break;
case 1 :
setColor(0xFFCC00) //1世代生き延びた(黄色)
break;
case 2 :
setColor(0x003399) //2世代生き延びた(青)
break;
default :
setColor(0x009900) //安定状態(グリーン)
break;
}
_lifeNum++
}else{
setColor(0x990000) //次に死ぬ(レッド)
}
}else{
_lifeNum = 0
}
}
private function setColor(color:int):void{
_sh.graphics.clear()
_sh.graphics.lineStyle(0,0xC0C0C0)
_sh.graphics.beginFill(color)
_sh.graphics.drawRect(0, 0, 10, 10)
_sh.graphics.endFill()
}
public function set id(n:int):void{
_id = n
}
public function get id():int{
return _id
}
}