/**
* 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();
}
}