gene

by hashito
MainStage
♥0 | Line 388 | Modified 2010-03-07 14:46:13 | MIT License
play

ActionScript3 source code

/**
 * Copyright hashito ( http://wonderfl.net/user/hashito )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/bPSd
 */

// MainStage
package {
	import flash.display.Sprite;
	[SWF(frameRate=60,width=456,height=456)]
	public class MainStage extends Sprite {
		public function MainStage(){
			addChild(new Main());
		}
	}
}

//---------------main---------------------
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.BlendMode;
import flash.filters.BlurFilter;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.events.*;
import flash.text.*;
import flash.utils.*;
import net.hires.debug.Stats;

class debug{
	private static var outobject:TextField=null;
	public static function init(s:TextField):void{outobject=s;}
	public static function out(s:String):void{ (outobject!=null)&&(outobject.appendText(s)); }
	public static function clear():void{(outobject!=null)&&(outobject.text="");}
}


// main class
class Main extends Sprite{
	// 遺伝関連
	private var map : MazeMap;
	private var poole : Poole;
	private var prototype : Individual;
	
	//オブジェクト関連
	private var updateTimer : Timer=new Timer(100);
	
	private var inputCol   :TextField = new TextField(); 
	private var inputRow   :TextField = new TextField(); 
	private var inputCount :TextField = new TextField(); 
	private var inputMut   :TextField = new TextField(); 
	private var inputTop   :TextField = new TextField(); 
	private var inputOdr   :TextField = new TextField(); 
	
	private var lblCol   :TextField = new TextField(); 
	private var lblRow   :TextField = new TextField(); 
	private var lblCount :TextField = new TextField(); 
	private var lblMut   :TextField = new TextField(); 
	private var lblTop   :TextField = new TextField(); 
	private var lblOdr   :TextField = new TextField(); 
	
	private var btnStart   :TextField = new TextField(); 
	private var btnStop    :TextField = new TextField(); 
	private var btnRenew   :TextField = new TextField(); 
	
	
	//private var debugout :TextField = new TextField(); // debug
		
	//Constructor
	public function Main() {addEventListener(Event.ADDED_TO_STAGE, init);}
	//init
	public function init(e:*):void{
		//debug init ★
		// debug.init(debugout);
		// debugout.autoSize = flash.text.TextFieldAutoSize.LEFT;
		// debugout.y=300;
		// addChild(debugout);
		//debug.out("hi");
		//try{
		//}catch(e:Error){
		//	debug.out(""+e);
		//}
		
		inputInit();
		lblInit();
		btnInit();
		
		setMap(30,30,100,0.01,0.3,30+30);
		updateStart();
		//var s:Stats = new Stats();
		//addChild(s);
	}
	
	public const OBJECT_STDPOINT_W:Number = 75;
	public const OBJECT_STDPOINT_H:Number = 20;
	
	// object init
	public function inputInit():void{
		// all
		inputCol.border = inputRow.border =  inputCount.border = inputMut.border = inputTop.border =  inputOdr.border =true;   
		inputCol.borderColor = inputRow.borderColor =  inputCount.borderColor = inputMut.borderColor = inputOdr.borderColor = inputTop.borderColor = 0x0;   
		inputCol.type = inputRow.type =  inputCount.type = inputMut.type =inputOdr.type = inputTop.type = flash.text.TextFieldType.INPUT;   
		inputCol.text ="30"; inputRow.text ="30";  inputCount.text ="100"; inputMut.text ="0.05";inputTop.text ="0.2"; inputOdr.text ="60";
		inputCol.x = OBJECT_STDPOINT_W*1; inputRow.x =OBJECT_STDPOINT_W*1;  inputCount.x=OBJECT_STDPOINT_W*3; inputMut.x=OBJECT_STDPOINT_W*3;inputTop.x=OBJECT_STDPOINT_W*5; inputOdr.x=OBJECT_STDPOINT_W*5; 
		inputCol.y = OBJECT_STDPOINT_H*0; inputRow.y =OBJECT_STDPOINT_H*1;  inputCount.y=OBJECT_STDPOINT_H*0; inputMut.y=OBJECT_STDPOINT_H*1;inputTop.y=OBJECT_STDPOINT_H*0; inputOdr.y=OBJECT_STDPOINT_H*1; 
		
		inputCol.width =  inputRow.width =  inputCount.width = lblMut.width = inputTop.width  = inputMut.width =inputOdr.width = OBJECT_STDPOINT_W; 
		inputCol.height=  inputRow.height=  inputCount.height= lblMut.height= inputTop.height = inputMut.height=inputOdr.height= OBJECT_STDPOINT_H; 
		addChild(inputCol);addChild(inputRow);addChild(inputCount);addChild(lblMut);addChild(inputTop);addChild(inputMut);addChild(inputOdr);
	}
	public function lblInit():void{
		// lblCol.backgroundColor = lblRow.backgroundColor  = lblCount.backgroundColor = lblMut.backgroundColor = lblTop.backgroundColor =0xffccff;
		lblCol.selectable = lblRow.selectable  = lblCount.selectable = lblMut.selectable = lblTop.selectable =lblOdr.selectable =false;
		lblCol.text ="col(+int)"; lblRow.text ="row(+int)";   lblCount.text ="個体数(+int)";  lblMut.text ="変異率(1~0)";  lblTop.text ="優秀種率(1~0)";  lblOdr.text ="歩数(+int)";
		lblCol.x = OBJECT_STDPOINT_W*0; lblRow.x =OBJECT_STDPOINT_W*0;  lblCount.x=OBJECT_STDPOINT_W*2; lblMut.x=OBJECT_STDPOINT_W*2;lblTop.x=OBJECT_STDPOINT_W*4; lblOdr.x=OBJECT_STDPOINT_W*4;
		lblCol.y = OBJECT_STDPOINT_H*0; lblRow.y =OBJECT_STDPOINT_H*1;  lblCount.y=OBJECT_STDPOINT_H*0; lblMut.y=OBJECT_STDPOINT_H*1;lblTop.y=OBJECT_STDPOINT_H*0; lblOdr.y=OBJECT_STDPOINT_H*1;
		lblCol.width =  lblRow.width =  lblCount.width = lblMut.width = lblTop.width  =lblOdr.width  = OBJECT_STDPOINT_W; 
		lblCol.height=  lblRow.height=  lblCount.height= lblMut.height= lblTop.height =lblOdr.height  = OBJECT_STDPOINT_H; 
		addChild(lblCol);addChild(lblRow);addChild(lblCount);addChild(lblMut);addChild(lblTop);addChild(lblOdr);
	}
	public function btnInit():void{
		btnStart.selectable = btnStop.selectable = btnRenew.selectable =false;
		btnStart.border = btnStop.border = btnRenew.border =true;
		btnStart.borderColor = btnStop.borderColor = btnRenew.borderColor =0xff00ff;
		
		btnStart.text = "start"; btnStop.text = "stop"; btnRenew.text = "renew";
		btnStart.x = btnStop.x = btnRenew.x  = 0 ;
		btnStart.y = OBJECT_STDPOINT_H*2 ;btnStop.y  = OBJECT_STDPOINT_H*3 ; btnRenew.y  = OBJECT_STDPOINT_H*4 ;
		btnStart.width = btnStop.width = btnRenew.width  = 50 ;
		btnStart.height = btnStop.height = btnRenew.height  = OBJECT_STDPOINT_H ;
		
		addChild(btnStart);addChild(btnStop);addChild(btnRenew);
		btnStart.addEventListener(MouseEvent.CLICK,updateStart);
		btnStop.addEventListener(MouseEvent.CLICK,updateStop);
		btnRenew.addEventListener(MouseEvent.CLICK,renew);
		
	}
	// 更新開始
	private function updateStart(e:MouseEvent=null):void{updateTimer.start();}
	// 更新停止
	private function updateStop(e:MouseEvent=null):void{updateTimer.stop();}
	// マップ更新
	private function renew(e:MouseEvent=null):void{
		function limit(x:Number,max:Number,min:Number):Number{
			debug.out(""+x);
			x=(x>max)?max:x;
			x=(x<min)?min:x;
			return x;
		}
		//
		var col:int = limit( int(inputCol.text) , 200 , 2);
		var row:int = limit( int(inputRow.text)  , 200 , 2);
		var count:int = limit( int(inputCount.text)  , 1024 , 1);
		var mut:Number = limit( Number(inputMut.text)  , 1 , 0);
		var top:Number = limit( Number(inputTop.text)  , 1 , 0);
		var odr:int = limit( int(inputTop.text)  , 1024*2 , 1);
		
		updateStop();
		removeMap();
		setMap(row,col,count,mut,top,odr);
		
		inputCol.text  = col.toString();
		inputRow.text  = row.toString();
		inputCount.text= count.toString();
		inputMut.text  = mut.toString();
		inputTop.text  = top.toString();
		inputOdr.text  = odr.toString();
	}
	
	//遺伝関係削除
	private function removeMap():void{
		// ガべコレに加えてくれるかな・・・
		removeChild(map);
		map=null;
		prototype=null;
		poole=null;
		
		// update
		updateTimer.stop();
		updateTimer.addEventListener(TimerEvent.TIMER,update);
		
	}
	//遺伝関係初期化
	private function setMap(row:int,col:int,count:int,mut:Number,top:Number,odr:int):void{
		
		// 削除
		if(map!=null)removeMap();
		
		//map init
		map = new MazeMap(row,col);
		map.x= map.y =50;
		map.setting(0,0,map.getCol()-1,map.getRow()-1);
		addChild(map);
		
		//poole init
		prototype=new Individual(new MazeGene(map,odr));//命令数は縦+横
		poole = new Poole(prototype,count,mut,top);
		
		
		// events
		// update
		var old:Date = new Date();
		update();
		updateTimer.delay=(new Date()).getTime() - old.getTime()+100;//ギリギリ怖いので100ms+
		updateTimer.addEventListener(TimerEvent.TIMER,update);
		
		
		// updateTimer.start();//update開始
	}
	//更新
	private function update(e:TimerEvent = null):void{
		poole.update();
		map.directions(MazeGene(poole.getTop().getGene()).getOrder());
		map.draw();
	}
}

//プール
class Poole extends Sprite{
	private var poole:Array = new Array();
	private var max:int;
	private var mutation:Number;	//突然変異率
	private var selection:Number;	//優秀な種の率
	private var prototype:Individual;
	private var topformer:Individual;
	
	public function Poole(prototype:Individual,max:int=100,mutation:Number=0.1,selection:Number=0.5){
		//debug.out("poole:max="+max+" mution="+mutation+" selection="+selection);
		this.max=max;
		this.mutation  = mutation;
		this.selection = selection;
		this.prototype = prototype;
		this.topformer = prototype.clone();
		for(var i:int=0;i<this.max;i++){
			poole[i] = prototype.clone();
		}
	}
	// 比較
	public function compare(a:Individual,b:Individual):int{
		return prototype.compare(a,b);
	}
	// 更新
	public function update():void{
		var unselection:int = max - Math.floor(max * selection);
		for(var i:int = 0 ; i < unselection ; i++ ){
			select().mating( select() , mutation, poole[ max - (i+1) ] as Individual);
		}
		poole.sort(compare);
		//歴代トップ更新
		if(compare(topformer,getTop()) < 0 )
			topformer.copyGene(getTop().getGene());
	}
	public function getTop():Individual{return poole[0] as Individual;}// 現トップ
	public function getTopformer():Individual{return topformer;}// 歴代トップ
	private function select():Individual{return poole[Math.floor( (max * selection) * Math.random() ) ] as Individual;}// 選択
}
//個体
class Individual{
	private var gene:IGene;
	public function getGene():IGene{return gene}
	public function copyGene(g:IGene):void{gene.copy(g);}
	public function Individual(g:IGene){gene=g;}
	public function compare(a:Individual,b:Individual):int{
		return gene.compare(a.getGene(),b.getGene());
	}
	public function clone():Individual{
		return new Individual(gene.clone());
	}
	public function mating(a:Individual,mutation:Number,cont:Individual):void{
		// debug.out("" + a +"@"+ mutation +"@"+ cont);
		this.gene.mating(a.getGene(),mutation,cont.getGene());
	}
}
//遺伝子
class IGene{
	public function compare(a:IGene,b:IGene):int{
		/*err*/ return 0xffffff;
	}
	public function mating(a:IGene,mutation:Number,cont:IGene):void{
		/*err*/ 
	}
	public function clone():IGene{
		/*err*/ return null;
	}
	public function copy(g:IGene):void{
		/*err*/ 
	}
}


//迷路 遺伝子
class MazeGene extends IGene{
	private var order:Array;
	private var map:MazeMap;
	//コンストラクタ
	public function MazeGene(map:MazeMap,len:int,seed:Array=null){
		this.map=map;
		if(seed==null){
			order=new Array(len);
		}else{
			order=seed;
		}
	}
	//命令取得
	public function getOrder():Array{
		return order;
	}
	public function mix():void{
		for(var i: int = 0;i<order.length;i++){
			order[i] = getRandomOrder();
		}
	}
	public function getRandomOrder():uint{
		return Math.floor(Math.random()*MazeMap.ORDER_MAX);
	}
	public override function compare(a:IGene,b:IGene):int{
		var scoreA:int = map.directions(MazeGene(a).getOrder());
		var scoreB:int = map.directions(MazeGene(b).getOrder());
		if(scoreA==scoreB){     return  0;
		}else if(scoreA>scoreB){return  1;
		}else{                  return -1;
		}
	}
	public override function mating(a:IGene,mutation:Number,cont:IGene):void{
		var ordc:Array = MazeGene(cont).getOrder();
		var orda:Array = MazeGene(a).getOrder();
		var cut:int = order.length/2;
		for(var i :int=0;i<order.length;i++){
			//突然変異
			if(mutation > Math.random()){ 
				ordc[i]= getRandomOrder();
			}else{
				//通常時
				if(i<=cut){	ordc[i]= order[i];
				}else{		ordc[i]= orda[i];
				}
			}
		}
	}
	public override function clone():IGene{
		return new MazeGene(map,order.length,order.concat());
	}
	public override function copy(g:IGene):void{
		var tg:Array=MazeGene(g).getOrder();
		for(var i :int=0;i<order.length;i++){
			order[i]=tg[i];
		}
	}
}
//迷路
class MazeMap extends Sprite{
	public static const COLOR_PLAYER:uint     = 0xff0000;
	public static const COLOR_FOOTPRINTS:uint = 0x005500;
	public static const COLOR_GOAL:uint       = 0xffff00;
	public static const COLOR_WALL:uint       = 0xCCCCCC;
	public static const COLOR_SPACE:uint      = 0xeeeeee;
	
	public static const ORDER_UP:uint         = 0x0;
	public static const ORDER_DOWN:uint       = 0x1;
	public static const ORDER_LEFT:uint       = 0x2;
	public static const ORDER_RIGHT:uint      = 0x3;
	public static const ORDER_MAX:uint       = 0x4;
	private var row:int;
	private var col:int;
	private var map:Array;
	
	private var start:Point  = new Point();
	private var player:Point = new Point();
	private var goal:Point   = new Point();
	private var wall:Array   = new Array();
	
	public function getRow():int{return row;}
	public function getCol():int{return col;}
	public function getColor(x:int,y:int):uint{
		return map[x][y];//範囲外指定すると異常発生
	}
	// 有効なポイント?
	public function isEnabledPoint(x:int,y:int):Boolean{
		return x>=0 && y>=0 && x<row && y<col;
	}
	//コンストラクタ
	public function MazeMap(row:int=100,col:int=100){
		this.row=row;
		this.col=col;
		map=new Array();
		
		for(var x:int=0 ;x<col;x++){
			map[x] = new Array();
			for(var y:int=0 ;y<row;y++){
				map[x][y] = COLOR_SPACE;
			}
		}
	}
	// 設定
	public function setting(stX:int,stY:int,glX:int,glY:int):Boolean{
		if(!isEnabledPoint(stX,stY))return false;
		if(!isEnabledPoint(glX,glY))return false;
		start.x=stX;
		start.y=stY;
		goal.x=glX;
		goal.y=glY;
		return true;
	}
	// スコア取得
	public function getScore():int{
		return  Math.abs(player.x-goal.x) +  Math.abs(player.y-goal.y);
	}
	//支持設定
	public function directions(order:Array):int{
		reset();
		for(var i:int = 0;i<order.length;i++){
			switch(order[i] as uint){
				case ORDER_RIGHT: playerMove( 1, 0); break;
				case ORDER_UP:    playerMove( 0,-1); break;
				case ORDER_DOWN:  playerMove( 0, 1); break;
				case ORDER_LEFT:  playerMove(-1, 0); break;
				default: /*err*/ break;
			}
			if(getScore()==0) return 0;//score ok
		}
		return getScore();
	}
	// プレーヤー移動
	public function playerMove(x:int,y:int):Boolean{
		x += player.x;
		y += player.y;
		if(!isEnabledPoint(x,y))return false;
		var c:uint = getColor(x,y);
		if(c==COLOR_WALL) return false;
		setFootprints(player.x,player.y);
		
		map[x][y]=COLOR_PLAYER;
		player.x = x;
		player.y = y;
		return true;
	}
	// リセット
	public function reset():void{
		for(var x:int=0 ;x<col;x++){
			map[x] = new Array();
			for(var y:int=0 ;y<row;y++){
				map[x][y] = COLOR_SPACE;
			}
		}
		for each(var p:Point in wall){
			map[p.x][p.y] = COLOR_WALL;
		}
		map[goal.x][goal.y] = COLOR_GOAL;
		map[start.x][start.y] = COLOR_PLAYER;
		player.x = start.x;
		player.y = start.y;
	}
	// 壁設定
	public function setWall(x:int,y:int):Boolean{
		if(!isEnabledPoint(x,y))return false;
		for each(var p:Point in wall){
			if(p.x == x && p.y == y)return false;
		}
		wall.push(new Point(x,y));
		return true;
	}
	// 壁削除
	public function removeWall(x:int,y:int):Boolean{
		if(! isEnabledPoint(x,y) )return false;
		for(var i:int=0;i<wall.length;i++)
		{
			var p:Point = Point(wall[i]);
			if(p.x == x && p.y == y){
				wall.splice(i,1);
				return true;
			}
		}
		
		return false;
	}
	//足跡追加
	private function setFootprints(x:int,y:int):Boolean{
		if(! isEnabledPoint(x,y))return false;
		map[x][y] = COLOR_FOOTPRINTS;
		return true;
	}
	//描画更新
	public function draw(width:Number=400,height:Number=400):void{
		var c:uint;
		var w:Number = width/col;
		var h:Number = height/row;
		
		graphics.clear();
		graphics.lineStyle(1,0x0);
		for(var x:int=0 ;x<col;x++){
			for(var y:int=0 ;y<row;y++){
				c = map[x][y] as uint;
				graphics.beginFill(c)
				graphics.drawRect(w*x,h*y,w,h);
			}
		}
		graphics.endFill();
	}
}