ライフゲーム(flash on 2009-8-19)

by krogue
todo: ランダム配置ボタン
note: gameのstep使ってない
♥0 | Line 199 | Modified 2009-08-19 17:05:24 | MIT License
play

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/cJXU
 */

// todo: ランダム配置ボタン
// note: gameのstep使ってない
package  {
	import flash.display.Sprite;
	import flash.display.Shape;
	import flash.display.Stage;
	import flash.display.SimpleButton;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	
	public class Life extends Sprite {
		private var isMouseDown:Boolean = false;
		private var timer:Timer;
		private var game:LifeGameSprite;
		private var start:TextField; // start/stop button
		private var reset:TextField; // reset button
		private var label:TextField;
		
		public function Life() {
			// timer
			timer = new Timer(500);
			// game
			game = addChild(new LifeGameSprite(20, 20, 12)) as LifeGameSprite;
			game.x = 100;
			game.y = 0;
			game.draw();
			// start/stop button
			start = addChild(createTextField("START", 1, 0)) as TextField;
			// reset button
			reset = addChild(createTextField("RESET", 1, 23)) as TextField;
			// label
			var text:String = "timer:" + timer.currentCount + "\ncount:" + game.count;
			label = addChild(createTextField(text, 2, 46)) as TextField;
			
			// event
			timer.addEventListener(TimerEvent.TIMER, timerHandler);
			start.addEventListener(MouseEvent.CLICK, startClickHandler);
			reset.addEventListener(MouseEvent.CLICK, resetClickHandler);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		
		private function createTextField(text:String, lines:Number, y:Number):TextField {
			var textFormat:TextFormat = new TextFormat();
			textFormat.align = TextFormatAlign.CENTER;
			textFormat.size = 12;
			textFormat.font = "Verdana";
			var textField:TextField = new TextField();
			textField.defaultTextFormat = textFormat;
			textField.text = text;
			textField.border = true;
			textField.width = 80;
			textField.height = 18 * lines;
			textField.x = 0;
			textField.y = y;
			textField.selectable = false;
			return textField;
		}
		
		private function timerHandler(event:TimerEvent):void {
			if (timer.currentCount >= 99999) {
				timer.stop();
			}
			this.game.next();
			label.text = "timer:" + timer.currentCount + "\ncount:" + game.count;
		}
		
		private function startClickHandler(event:MouseEvent):void {
			if (timer.running) {
				start.text = "START";
				timer.stop();
			} else {
				start.text = "STOP";
				timer.start();
			}
		}
		
		private function resetClickHandler(event:MouseEvent):void {
			timer.reset();
			game.reset();
			start.text = "START";
			label.text = "timer:" + timer.currentCount + "\ncount:" + game.count;
		}
		
		private function mouseDownHandler(event:MouseEvent):void {
			if (!timer.running && !isMouseDown) {
				isMouseDown = true;
				this.game.click(event.stageX, event.stageY);
			}
		}
		
		private function mouseUpHandler(event:MouseEvent):void {
			isMouseDown = false;
		}
		
		private function mouseMoveHandler(event:MouseEvent):void {
			if (!timer.running && isMouseDown) {
				this.game.click(event.stageX, event.stageY);
			}
		}
		
		private function enterFrameHandler(event:Event):void {
			this.game.draw();
		}
	}
}

import flash.display.Sprite;
import flash.display.Shape;
import flash.display.Graphics;

class LifeGameSprite extends Sprite {
	private var step:Number; // next 実行回数
	private var lines:Array; // Cell からなる2次元配列
	
	public function LifeGameSprite(cols:uint, rows:uint, size:Number) {
		var margin:int = size / 3;
		var lines:Array = new Array();
		for (var row:int = 0; row < rows; row++) {
			var line:Array = new Array();
			for (var col:int = 0; col < cols; col++) {
				var cell:Cell = new Cell(size, false);
				cell.x = col * (size + margin);
				cell.y = row * (size + margin);
				line.push(cell);
				addChild(cell); // 子にも追加
			}
			lines.push(line)
		}
		this.lines = lines;
		this.step = 0;
	}

	public function draw():void {
		lines.forEach(function(line:*, row:int, lines:Array):void {
			line.forEach(function(cell:*, col:int, line:Array):void {
				cell.draw();
			}, this);
		}, this);
	}
	
	// クリックされたCellを誕生させる
	public function click(stageX:Number, stageY:Number):void {
		lines.forEach(function(line:*, row:int, lines:Array):void {
			line.forEach(function(cell:*, col:int, line:Array):void {
				if (cell.hitTestPoint(stageX, stageY)) {
					cell.live = true;
				}
			}, this);
		}, this);
	}
	
	public function reset():void {
		// lines のリセット
		lines.forEach(function(line:*, row:int, lines:Array):void {
			line.forEach(function(cell:*, col:int, line:Array):void {
				cell.live = false;
			}, this);
		}, this);
		// step のリセット
		this.step = 0;
	}
	
	public function next():void {
		// 生きているかのみを格納した配列の作成(状態更新の準備)
		var afterLines:Array = lines.map(function(line:*, row:int, lines:Array):Array {
			return line.map(function(cell:*, col:int, line:Array):Boolean {
				// 周囲の生存数を取得
				var liveCount:int = 0;
				var pline:Array = lines[row - 1];
				var nline:Array = lines[row + 1];
				if (pline) {
					if (pline[col - 1] && pline[col - 1].live) liveCount++;
					if (pline[col + 0] && pline[col + 0].live) liveCount++;
					if (pline[col + 1] && pline[col + 1].live) liveCount++;
				}
				if (line[col - 1] && line[col - 1].live) liveCount++;
				if (line[col + 1] && line[col + 1].live) liveCount++;
				if (nline) {
					if (nline[col - 1] && nline[col - 1].live) liveCount++;
					if (nline[col + 0] && nline[col + 0].live) liveCount++;
					if (nline[col + 1] && nline[col + 1].live) liveCount++;
				}
				// 周囲の生存数が、3個なら無条件に生存、2個かつ生存でも生存、それ以外は死亡
				return ((liveCount == 3) || (liveCount == 2 && cell.live));
			}, this);
		}, this);
		
		// 状態の更新
		lines.forEach(function(line:*, row:int, lines:Array):void {
			line.forEach(function(cell:*, col:int, line:Array):void {
				cell.live = afterLines[row][col];
			}, this);
		}, this);
	}
	
	public function get count():Number {
		var count:Number = 0;
		lines.forEach(function(line:*, row:int, lines:Array):void {
			line.forEach(function(cell:*, col:int, line:Array):void {
				count += (cell.live ? 1 : 0);
			}, this);
		}, this);
		return count;
	}
}

// getter/setter を使ってみた
class Cell extends Shape {
	private var _live:Boolean;
	private var size:Number;
	
	public function Cell(size:Number, live:Boolean=true) {
		this.size = size;
		_live = live;
	}
	
	public function get live():Boolean {
		return _live;
	}
	
	public function set live(value:Boolean):void {
		_live = value;
	}
	
	public function draw():void {
		graphics.clear();
		graphics.lineStyle(1, 0x000000);
		graphics.beginFill(0x000000, (_live ? 0.5 : 0));
		graphics.drawRect(0, 0, size, size);
		graphics.endFill();
	}
}